/*
 * Copyright (c) 2014, 2015-2017, 2020-2021 The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include <common.h>
#include <pci.h>

#include <linux/sizes.h>
#include <asm/io.h>
#include <asm/errno.h>
#include <asm/arch-qca-common/gpio.h>
#include <asm/arch-qca-common/iomap.h>
#include <fdtdec.h>
#include <dm.h>

DECLARE_GLOBAL_DATA_PTR;

#define PCIE_RST_CTRL_PIPE_ARES			0x4
#define PCIE_RST_CTRL_PIPE_STICKY_ARES		0x100
#define PCIE_RST_CTRL_PIPE_PHY_AHB_ARES		0x800
#define PCIE_RST_CTRL_AXI_M_ARES		0x1
#define PCIE_RST_CTRL_AXI_M_STICKY_ARES		0x80
#define PCIE_RST_CTRL_AXI_S_ARES		0x2
#define PCIE_RST_CTRL_AHB_ARES			0x400


#define PCI_CFG0_RDWR			0x4
#define PCI_CFG1_RDWR			0x5
#define RD				0
#define WR 				1

#define MSM_PCIE_DEV_CFG_ADDR                   0x01000000
#define PCIE20_PLR_IATU_VIEWPORT		0x900
#define PCIE20_PLR_IATU_CTRL1			0x904
#define PCIE20_PLR_IATU_CTRL2			0x908
#define PCIE20_PLR_IATU_LBAR			0x90C
#define PCIE20_PLR_IATU_UBAR			0x910
#define PCIE20_PLR_IATU_LAR			0x914
#define PCIE20_PLR_IATU_LTAR			0x918
#define PCIE20_PLR_IATU_UTAR			0x91c

/* PCIE20_PARF_PHYS Registers */
#define PARF_SLV_ADDR_SPACE_SIZE		0x16C
#define SLV_ADDR_SPACE_SZ			0x40000000
#define PCIE_0_PCIE20_PARF_LTSSM		0x1B0
#define LTSSM_EN				(1 << 8)
/* PCIE20_PHYS Registers */
#define PCIE_0_PORT_FORCE_REG			0x708
#define PCIE_0_ACK_F_ASPM_CTRL_REG		0x70C
#define L1_ENTRANCE_LATENCY(x)			(x << 27)
#define L0_ENTRANCE_LATENCY(x)			(x << 24)
#define COMMON_CLK_N_FTS(x)			(x << 16)
#define ACK_N_FTS(x)				(x << 8)

#define PCIE_0_GEN2_CTRL_REG			0x80C
#define FAST_TRAINING_SEQ(x)			(x << 0)
#define NUM_OF_LANES(x)				(x << 8)
#define DIRECT_SPEED_CHANGE			(1 << 17)

#define PCIE_0_TYPE0_STATUS_COMMAND_REG_1	0x004
#define PCI_TYPE0_BUS_MASTER_EN			(1 << 2)

#define PCIE_0_MISC_CONTROL_1_REG		0x8BC
#define DBI_RO_WR_EN				(1 << 0)

#define PCIE_0_LINK_CAPABILITIES_REG		0x07C
#define PCIE_CAP_ASPM_OPT_COMPLIANCE		(1 << 22)
#define PCIE_CAP_LINK_BW_NOT_CAP		(1 << 21)
#define PCIE_CAP_DLL_ACTIVE_REP_CAP		(1 << 20)
#define PCIE_CAP_L1_EXIT_LATENCY(x)		(x << 15)
#define PCIE_CAP_L0S_EXIT_LATENCY(x)		(x << 12)
#define PCIE_CAP_MAX_LINK_WIDTH(x)		(x << 4)
#define PCIE_CAP_MAX_LINK_SPEED(x)		(x << 0)

#define PCIE_0_DEVICE_CONTROL2_DEVICE_STATUS2_REG	0x098
#define PCIE_CAP_CPL_TIMEOUT_DISABLE			(1 << 4)
#define PCIE_0_TYPE0_LINK_CONTROL_LINK_STATUS_REG_1	0x080
#define PCIE20_AXI_MSTR_RESP_COMP_CTRL0                 0x818
#define PCIE20_AXI_MSTR_RESP_COMP_CTRL1                 0x81c

#define PCIE20_SIZE   			SZ_4K
#define PCIE_AXI_CONF_SIZE   		SZ_1M

#define PCIE_USB3_PCS_POWER_DOWN_CONTROL		0x804
#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN			0x34
#define QSERDES_COM_CLK_ENABLE1				0x38
#define QSERDES_COM_BG_TRIM				0x70
#define QSERDES_COM_LOCK_CMP_EN				0xC8
#define QSERDES_COM_VCO_TUNE_MAP			0x128
#define QSERDES_COM_VCO_TUNE_TIMER1			0x144
#define QSERDES_COM_VCO_TUNE_TIMER2			0x144
#define QSERDES_COM_CMN_CONFIG				0x194
#define PCIE_QSERDES_COM_PLL_IVCO			0x48
#define QSERDES_COM_HSCLK_SEL				0x178
#define PCIE_QSERDES_COM_SVS_MODE_CLK_SEL		0x19C
#define PCIE_QSERDES_COM_CORE_CLK_EN			0x18C
#define QSERDES_COM_CORECLK_DIV				0x184
#define QSERDES_COM_RESETSM_CNTRL			0xB4
#define PCIE_QSERDES_COM_BG_TIMER			0xC
#define PCIE_QSERDES_COM_SYSCLK_EN_SEL			0xAC
#define PCIE_QSERDES_COM_DEC_START_MODE0		0xD0
#define PCIE_QSERDES_COM_DIV_FRAC_START3_MODE0		0xE4
#define PCIE_QSERDES_COM_DIV_FRAC_START2_MODE0		0xE0
#define PCIE_QSERDES_COM_DIV_FRAC_START1_MODE0		0xDC
#define QSERDES_COM_LOCK_CMP3_MODE0			0x54
#define QSERDES_COM_LOCK_CMP2_MODE0			0x50
#define PCIE_QSERDES_COM_LOCK_CMP1_MODE0		0x4C
#define QSERDES_COM_CLK_SELECT				0x174
#define PCIE_QSERDES_COM_SYS_CLK_CTRL			0x3C
#define QSERDES_COM_SYSCLK_BUF_ENABLE			0x40
#define QSERDES_COM_CP_CTRL_MODE0			0x78
#define QSERDES_COM_PLL_RCTRL_MODE0			0x84
#define QSERDES_COM_PLL_CCTRL_MODE0			0x90
#define QSERDES_COM_INTEGLOOP_GAIN1_MODE0		0x10C
#define QSERDES_COM_INTEGLOOP_GAIN0_MODE0		0x108
#define QSERDES_COM_BIAS_EN_CTRL_BY_PSM			0xA8
#define QSERDES_COM_VCO_TUNE_CTRL			0xC
#define QSERDES_COM_SSC_EN_CENTER			0x10
#define PCIE_QSERDES_COM_SSC_PER1			0x1C
#define QSERDES_COM_SSC_PER2				0x20
#define QSERDES_COM_SSC_ADJ_PER1			0x14
#define QSERDES_COM_SSC_ADJ_PER2			0x18
#define QSERDES_COM_SSC_STEP_SIZE1			0x24
#define QSERDES_COM_SSC_STEP_SIZE2			0x28
#define QSERDES_TX_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN     0x268
#define QSERDES_TX_LANE_MODE                            0x294
#define QSERDES_TX_RES_CODE_LANE_OFFSET                 0x254
#define PCIE_QSERDES_TX_RCV_DETECT_LVL_2                0x2AC
#define QSERDES_RX_SIGDET_ENABLES                       0x510
#define PCIE_QSERDES_RX_SIGDET_DEGLITCH_CNTRL           0x51C
#define PCIE_QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2           0x4D8
#define PCIE_QSERDES_RX_RX_EQU_ADAPTOR_CNTRL3           0x4DC
#define PCIE_QSERDES_RX_RX_EQU_ADAPTOR_CNTRL4           0x4E0
#define QSERDES_RX_UCDR_SO_SATURATION_AND_ENABLE        0x448
#define PCIE_QSERDES_RX_UCDR_SO_GAIN                    0x41C
#define QSERDES_RX_UCDR_SO_GAIN_HALF                    0x410
#define QSERDES_COM_CLK_EP_DIV                          0x74
#define PCIE_USB3_PCS_ENDPOINT_REFCLK_DRIVE             0x854
#define PCIE_USB3_PCS_OSC_DTCT_ACTIONS                  0x9AC
#define PCIE_USB3_PCS_PWRUP_RESET_DLY_TIME_AUXCLK       0x8A0
#define PCIE_USB3_PCS_L1SS_WAKEUP_DLY_TIME_AUXCLK_MSB   0x9E0
#define PCIE_USB3_PCS_L1SS_WAKEUP_DLY_TIME_AUXCLK_LSB   0x9DC
#define PCIE_USB3_PCS_PLL_LOCK_CHK_DLY_TIME_AUXCLK_LSB  0x9A8
#define PCIE_USB3_PCS_LP_WAKEUP_DLY_TIME_AUXCLK         0x8A4
#define PCIE_USB3_PCS_PLL_LOCK_CHK_DLY_TIME             0x8A8
#define QSERDES_RX_SIGDET_CNTRL                         0x514
#define PCIE_USB3_PCS_RX_SIGDET_LVL                     0x9D8
#define PCIE_USB3_PCS_TXDEEMPH_M6DB_V0                  0x824
#define PCIE_USB3_PCS_TXDEEMPH_M3P5DB_V0                0x828
#define PCIE_USB3_PCS_SW_RESET                          0x800
#define PCIE_USB3_PCS_START_CONTROL                     0x808

#define PCIE20_PARF_PHY_CTRL		0x40
#define PHY_CTRL_PHY_TX0_TERM_OFFSET_MASK       (0x1f << 16)
#define PHY_CTRL_PHY_TX0_TERM_OFFSET(x)         (x << 16)

#define PCIE20_PARF_PHY_REFCLK		0x4C
#define REF_SSP_EN				BIT(16)
#define REF_USE_PAD				BIT(12)

#define PCIE20_PARF_PCS_DEEMPH		0x34
#define PCIE20_PARF_PCS_DEEMPH_TX_DEEMPH_GEN1(x) (x << 16)
#define PCIE20_PARF_PCS_DEEMPH_TX_DEEMPH_GEN2_3_5DB(x) (x << 8)
#define PCIE20_PARF_PCS_DEEMPH_TX_DEEMPH_GEN2_6DB(x) (x << 0)

#define PCIE20_PARF_PCS_SWING		0x38
#define PCIE20_PARF_PCS_SWING_TX_SWING_FULL(x)	(x << 8)
#define PCIE20_PARF_PCS_SWING_TX_SWING_LOW(x)	(x << 0)

#define PCIE20_PARF_CONFIG_BITS		0x50

#define PCIE_SFAB_AXI_S5_FCLK_CTL 	0x00902154

#define PCIE20_ELBI_SYS_CTRL		0x04

#define PCS_COM_POWER_DOWN_CONTROL		0x840
#define PCIE_0_QSERDES_PLL_BIAS_EN_CLKBUFLR_EN	0x03C
#define PCIE_0_QSERDES_PLL_BIAS_EN_CTRL_BY_PSM	0x0A4
#define PCIE_0_QSERDES_PLL_CLK_SELECT		0x16C
#define PCIE_0_QSERDES_PLL_PLL_IVCO		0x050

#define PCIE_0_QSERDES_PLL_BG_TRIM		0x074
#define PCIE_0_QSERDES_PLL_CMN_CONFIG		0x18C
#define PCIE_0_QSERDES_PLL_LOCK_CMP_EN		0x0C4
#define PCIE_0_QSERDES_PLL_RESETSM_CNTRL	0x0B0
#define PCIE_0_QSERDES_PLL_SVS_MODE_CLK_SEL	0x194
#define PCIE_0_QSERDES_PLL_VCO_TUNE_MAP		0x120
#define PCIE_0_QSERDES_PLL_VCO_TUNE_TIMER1	0x13C
#define PCIE_0_QSERDES_PLL_VCO_TUNE_TIMER2	0x140
#define PCIE_0_QSERDES_PLL_CORE_CLK_EN		0x184
#define PCIE_0_QSERDES_PLL_HSCLK_SEL		0x170
#define PCIE_0_QSERDES_PLL_DEC_START_MODE0	0x0CC
#define PCIE_0_QSERDES_PLL_DIV_FRAC_START3_MODE0 0x0E0
#define PCIE_0_QSERDES_PLL_DIV_FRAC_START2_MODE0 0x0DC
#define PCIE_0_QSERDES_PLL_DIV_FRAC_START1_MODE0 0x0D8
#define PCIE_0_QSERDES_PLL_LOCK_CMP2_MODE0	0x058
#define PCIE_0_QSERDES_PLL_LOCK_CMP1_MODE0	0x054
#define PCIE_0_QSERDES_PLL_CP_CTRL_MODE0	0x080
#define PCIE_0_QSERDES_PLL_PLL_RCTRL_MODE0	0x088
#define PCIE_0_QSERDES_PLL_PLL_CCTRL_MODE0	0x090
#define PCIE_0_QSERDES_PLL_INTEGLOOP_GAIN1_MODE0 0x104
#define PCIE_0_QSERDES_PLL_INTEGLOOP_GAIN0_MODE0 0x100
#define PCIE_0_QSERDES_PLL_VCO_TUNE2_MODE0	0x128
#define PCIE_0_QSERDES_PLL_VCO_TUNE1_MODE0	0x124
#define PCIE_0_QSERDES_PLL_CORECLK_DIV		0x17C
#define PCIE_0_QSERDES_PLL_SYS_CLK_CTRL		0x044
#define PCIE_0_QSERDES_PLL_SYSCLK_BUF_ENABLE	0x048
#define PCIE_0_QSERDES_PLL_SYSCLK_EN_SEL	0x0A8
#define PCIE_0_QSERDES_PLL_BG_TIMER		0x00C
#define PCIE_0_QSERDES_PLL_DEC_START_MODE1	0x0D0
#define PCIE_0_QSERDES_PLL_DIV_FRAC_START3_MODE1 0x0EC
#define PCIE_0_QSERDES_PLL_DIV_FRAC_START2_MODE1 0x0E8
#define PCIE_0_QSERDES_PLL_DIV_FRAC_START1_MODE1 0x0E4
#define PCIE_0_QSERDES_PLL_LOCK_CMP2_MODE1	0x064
#define PCIE_0_QSERDES_PLL_LOCK_CMP1_MODE1	0x060
#define PCIE_0_QSERDES_PLL_CP_CTRL_MODE1	0x084
#define PCIE_0_QSERDES_PLL_PLL_RCTRL_MODE1	0x08C
#define PCIE_0_QSERDES_PLL_PLL_CCTRL_MODE1	0x094
#define PCIE_0_QSERDES_PLL_INTEGLOOP_GAIN1_MODE1 0x10C
#define PCIE_0_QSERDES_PLL_INTEGLOOP_GAIN0_MODE1 0x108
#define PCIE_0_QSERDES_PLL_VCO_TUNE2_MODE1	0x130
#define PCIE_0_QSERDES_PLL_VCO_TUNE1_MODE1	0x12C
#define PCIE_0_QSERDES_PLL_CORECLK_DIV_MODE1	0x1B4
#define PCIE_0_QSERDES_TX0_RES_CODE_LANE_OFFSET_TX 0x23C
#define PCIE_0_QSERDES_TX0_RCV_DETECT_LVL_2	0x29C
#define PCIE_0_QSERDES_TX0_HIGHZ_DRVR_EN	0x258
#define PCIE_0_QSERDES_TX0_LANE_MODE_1		0x284
#define PCIE_0_QSERDES_RX0_SIGDET_CNTRL		0x51C
#define	PCIE_0_QSERDES_RX0_SIGDET_ENABLES	0x518
#define PCIE_0_QSERDES_RX0_SIGDET_DEGLITCH_CNTRL 0x524
#define PCIE_0_QSERDES_RX0_RX_EQU_ADAPTOR_CNTRL2 0x4EC
#define PCIE_0_QSERDES_RX0_RX_EQU_ADAPTOR_CNTRL3 0x4F0
#define PCIE_0_QSERDES_RX0_RX_EQU_ADAPTOR_CNTRL4 0x4F4
#define PCIE_0_QSERDES_RX0_DFE_EN_TIMER		0x5B4
#define PCIE_0_QSERDES_RX0_UCDR_SO_SATURATION_AND_ENABLE 0x434
#define PCIE_0_QSERDES_RX0_UCDR_PI_CONTROLS	0x444
#define PCIE_0_QSERDES_RX0_RX_EQ_OFFSET_ADAPTOR_CNTRL1 0x510
#define PCIE_0_QSERDES_RX0_RX_OFFSET_ADAPTOR_CNTRL2 0x514
#define PCIE_0_QSERDES_RX0_RX_MODE_10_LOW	0x598
#define PCIE_0_QSERDES_RX0_RX_MODE_10_HIGH	0x59C
#define PCIE_0_QSERDES_RX0_RX_MODE_10_HIGH2	0x5A0
#define PCIE_0_QSERDES_RX0_RX_MODE_10_HIGH3	0x5A4
#define PCIE_0_QSERDES_RX0_RX_MODE_10_HIGH4	0x5A8
#define PCIE_0_QSERDES_RX0_RX_MODE_01_LOW	0x584
#define PCIE_0_QSERDES_RX0_RX_MODE_01_HIGH	0x588
#define PCIE_0_QSERDES_RX0_RX_MODE_01_HIGH2	0x58C
#define PCIE_0_QSERDES_RX0_RX_MODE_01_HIGH3	0x590
#define PCIE_0_QSERDES_RX0_RX_MODE_01_HIGH4	0x594
#define PCIE_0_QSERDES_RX0_RX_MODE_00_LOW	0x570
#define PCIE_0_QSERDES_RX0_RX_MODE_00_HIGH	0x574
#define PCIE_0_QSERDES_RX0_RX_MODE_00_HIGH2	0x578
#define PCIE_0_QSERDES_RX0_RX_MODE_00_HIGH3	0x57C
#define PCIE_0_QSERDES_RX0_RX_MODE_00_HIGH4	0x580
#define PCIE_0_QSERDES_RX0_RX_IDAC_TSETTLE_HIGH 0x4FC
#define PCIE_0_QSERDES_RX0_RX_IDAC_TSETTLE_LOW	0x4F8

#define PCIE_0_PCS_COM_FLL_CNTRL2		0x89C
#define PCIE_0_PCS_COM_FLL_CNT_VAL_L		0x8A0
#define PCIE_0_PCS_COM_FLL_CNT_VAL_H_TOL	0x8A4
#define PCIE_0_PCS_COM_FLL_MAN_CODE		0x8A8
#define PCIE_0_PCS_COM_FLL_CNTRL1		0x898

#define PCIE_0_PCS_COM_P2U3_WAKEUP_DLY_TIME_AUXCLK_H 0x9A8
#define PCIE_0_PCS_COM_P2U3_WAKEUP_DLY_TIME_AUXCLK_L 0x9A4

#define PCIE_0_PCS_PCIE_OSC_DTCT_ACTIONS	0xC90
#define PCIE_0_PCS_PCIE_L1P1_WAKEUP_DLY_TIME_AUXCLK_H 0xC44
#define PCIE_0_PCS_PCIE_L1P1_WAKEUP_DLY_TIME_AUXCLK_L 0xC40
#define PCIE_0_PCS_PCIE_L1P2_WAKEUP_DLY_TIME_AUXCLK_H 0xC4C
#define PCIE_0_PCS_PCIE_L1P2_WAKEUP_DLY_TIME_AUXCLK_L 0xC48
#define PCIE_0_PCS_PCIE_EQ_CONFIG1		0xCA0
#define PCIE_0_PCS_PCIE_EQ_CONFIG2		0xCA4

#define PCIE_0_PCS_PCIE_POWER_STATE_CONFIG4	0xC14
#define PCIE_0_PCS_PCIE_OSC_DTCT_CONFIG2	0xC5C
#define PCIE_0_PCS_PCIE_OSC_DTCT_MODE2_CONFIG2	0xC78
#define PCIE_0_PCS_PCIE_OSC_DTCT_MODE2_CONFIG4	0xC80
#define PCIE_0_PCS_PCIE_OSC_DTCT_MODE2_CONFIG5	0xC84

#define PCIE_0_QSERDES_PLL_CLK_EP_DIV_MODE0	0x078
#define PCIE_0_QSERDES_PLL_CLK_EP_DIV_MODE1	0x07C
#define PCIE_0_QSERDES_PLL_CLK_ENABLE1		0x040

#define PCIE_0_PCS_COM_POWER_DOWN_CONTROL	0x840
#define PCIE_0_PCS_PCIE_ENDPOINT_REFCLK_DRIVE	0xC1C
#define PCIE_0_PCS_COM_RX_DCC_CAL_CONFIG	0x9D8
#define PCIE_0_PCS_COM_RX_SIGDET_LVL		0x988
#define PCIE_0_PCS_COM_REFGEN_REQ_CONFIG1	0x8DC
#define PCIE_0_PCS_COM_SW_RESET			0x800
#define PCIE_0_PCS_COM_START_CONTROL		0x844

#define PCIE_0_QSERDES_PLL_SSC_PER1		0x01C
#define PCIE_0_QSERDES_PLL_SSC_PER2		0x020
#define PCIE_0_QSERDES_PLL_SSC_STEP_SIZE1_MODE0	0x024
#define PCIE_0_QSERDES_PLL_SSC_STEP_SIZE2_MODE0	0x028
#define PCIE_0_QSERDES_PLL_SSC_STEP_SIZE1_MODE1	0x02C
#define PCIE_0_QSERDES_PLL_SSC_STEP_SIZE2_MODE1	0x030
#define PCIE_0_QSERDES_RX0_UCDR_FO_GAIN		0x408
#define PCIE_0_QSERDES_RX0_UCDR_SO_GAIN		0x414
#define PCIE_0_PCS_COM_G12S1_TXDEEMPH_M3P5DB	0x96C
#define PCIE_0_PCS_COM_EQ_CONFIG5		0x9EC
#define PCIE_0_PCS_PCIE_POWER_STATE_CONFIG2	0xC0C
#define PCIE_0_PCS_PCIE_PRESET_P10_PRE		0xCBC
#define PCIE_0_PCS_PCIE_PRESET_P10_POST		0xCE0

#define PCIE_0_QSERDES_PLL_SSC_EN_CENTER	0x010
#define PCIE_0_QSERDES_PLL_SSC_ADJ_PER1		0x014
#define PCIE_0_QSERDES_PLL_SSC_ADJ_PER2		0x018

#define PCIE_0_QSERDES_TX1_RES_CODE_LANE_OFFSET_TX		0x63C
#define PCIE_0_QSERDES_TX1_RCV_DETECT_LVL_2			0x69C
#define PCIE_0_QSERDES_TX1_HIGHZ_DRVR_EN			0x658
#define PCIE_0_QSERDES_TX1_LANE_MODE_1				0x684
#define PCIE_0_QSERDES_RX1_SIGDET_CNTRL				0x91C
#define PCIE_0_QSERDES_RX1_SIGDET_ENABLES			0x918
#define PCIE_0_QSERDES_RX1_SIGDET_DEGLITCH_CNTRL		0x924
#define PCIE_0_QSERDES_RX1_RX_EQU_ADAPTOR_CNTRL2		0x8EC
#define PCIE_0_QSERDES_RX1_RX_EQU_ADAPTOR_CNTRL3		0x8F0
#define PCIE_0_QSERDES_RX1_RX_EQU_ADAPTOR_CNTRL4		0x8F4
#define PCIE_0_QSERDES_RX1_DFE_EN_TIMER				0x9B4
#define PCIE_0_QSERDES_RX1_UCDR_FO_GAIN				0x808
#define PCIE_0_QSERDES_RX1_UCDR_SO_GAIN				0x814
#define PCIE_0_QSERDES_RX1_UCDR_SO_SATURATION_AND_ENABLE	0x834
#define PCIE_0_QSERDES_RX1_UCDR_PI_CONTROLS			0x844
#define PCIE_0_QSERDES_RX1_RX_EQ_OFFSET_ADAPTOR_CNTRL1		0x910
#define PCIE_0_QSERDES_RX1_RX_OFFSET_ADAPTOR_CNTRL2		0x914
#define PCIE_0_QSERDES_RX1_RX_MODE_10_LOW			0x998
#define PCIE_0_QSERDES_RX1_RX_MODE_10_HIGH			0x99C
#define PCIE_0_QSERDES_RX1_RX_MODE_10_HIGH2			0x9A0
#define PCIE_0_QSERDES_RX1_RX_MODE_10_HIGH3			0x9A4
#define PCIE_0_QSERDES_RX1_RX_MODE_10_HIGH4			0x9A8
#define PCIE_0_QSERDES_RX1_RX_MODE_01_LOW			0x984
#define PCIE_0_QSERDES_RX1_RX_MODE_01_HIGH			0x988
#define PCIE_0_QSERDES_RX1_RX_MODE_01_HIGH2			0x98C
#define PCIE_0_QSERDES_RX1_RX_MODE_01_HIGH3			0x990
#define PCIE_0_QSERDES_RX1_RX_MODE_01_HIGH4			0x994
#define PCIE_0_QSERDES_RX1_RX_MODE_00_LOW			0x970
#define PCIE_0_QSERDES_RX1_RX_MODE_00_HIGH			0x974
#define PCIE_0_QSERDES_RX1_RX_MODE_00_HIGH2			0x978
#define PCIE_0_QSERDES_RX1_RX_MODE_00_HIGH3			0x97C
#define PCIE_0_QSERDES_RX1_RX_MODE_00_HIGH4			0x980
#define PCIE_0_QSERDES_RX1_RX_IDAC_TSETTLE_HIGH			0x8FC
#define PCIE_0_QSERDES_RX1_RX_IDAC_TSETTLE_LOW			0x8F8
#define PCIE_0_QSERDES_RX1_RX_MODE_00_HIGH3			0x97C

#define PCIE_0_PCS_PCIE_OSC_DTCT_CONFIG1			0xC58
#define PCIE_0_PCS_PCIE_OSC_DTCT_CONFIG4			0xC64
#define PCIE_0_PCS_PCIE_INT_AUX_CLK_CONFIG1			0xC50
#define PCIE_0_PCS_PCIE_OSC_DTCT_MODE2_CONFIG6			0xC88

#define PARF_MHI_CLOCK_RESET_CTRL		0x174
#define BYPASS					BIT(4)
#define MSTR_AXI_CLK_EN				BIT(1)
#define AHB_CLK_EN				BIT(0)

#define PCIE_PARF_DEVICE_TYPE			0x1000
#define DEVICE_TYPE_RC				0x4


#define PCIE30_GEN3_RELATED_OFF			0x890
#define GEN3_EQUALIZATION_DISABLE		BIT(16)
#define RXEQ_RGRDLESS_RXTS			BIT(13)
#define GEN3_ZRXDC_NONCOMPL			BIT(0)

#define PCIE20_PARF_SYS_CTRL			0x00
#define ECAM_BLOCKER_EN_RANGE2			BIT(30)
#define MAC_PHY_POWERDOWN_IN_P2_D_MUX_EN	BIT(29)
#define ECAM_REMOVE_OFFSET_EN			BIT(27)
#define ECAM_BLOCKER_EN				BIT(26)
#define MST_WAKEUP_EN				BIT(13)
#define SLV_WAKEUP_EN				BIT(12)
#define MSTR_ACLK_CGC_DIS			BIT(10)
#define SLV_ACLK_CGC_DIS			BIT(9)
#define CORE_CLK_CGC_DIS			BIT(6)
#define AUX_PWR_DET				BIT(4)
#define CORE_CLK_2AUX_CLK_MUX_DIS		BIT(3)
#define L23_CLK_RMV_DIS				BIT(2)
#define L1_CLK_RMV_DIS				BIT(1)

#define PARF_BLOCK_SLV_AXI_WR_BASE		0x360
#define PARF_BLOCK_SLV_AXI_WR_LIMIT		0x368
#define PARF_BLOCK_SLV_AXI_RD_BASE		0x370
#define PARF_BLOCK_SLV_AXI_RD_LIMIT 		0x378
#define PARF_ECAM_BASE				0x380
#define PARF_ECAM_OFFSET_REMOVAL_BASE		0x388
#define PARF_ECAM_OFFSET_REMOVAL_LIMIT		0x390
#define PARF_BLOCK_SLV_AXI_WR_BASE_2		0x398
#define PARF_BLOCK_SLV_AXI_WR_LIMIT_2		0x3A0
#define PARF_BLOCK_SLV_AXI_RD_BASE_2		0x3A8
#define PARF_BLOCK_SLV_AXI_RD_LIMIT_2		0x3B0
#define PARF_BDF_TO_SID_TABLE			0x2000

#define PCIE20_LNK_CONTROL2_LINK_STATUS2        0xA0
#define PCIE_CAP_CURR_DEEMPHASIS		BIT(16)
#define SPEED_GEN3				0x3

#define PCIE_PHY_DELAY_MS			0xFFFFFFFF

#if defined(CONFIG_IPQ9574) || defined(CONFIG_IPQ5332)
#define QCN_VENDOR_ID				0x17CB
#define QCN9224_DEVICE_ID			0x1109
#define QCN9000_DEVICE_ID 			0x1104
#define QCN6432_DEVICE_ID			0x110c
#define MAX_UNWINDOWED_ADDRESS                  0x80000
#define WINDOW_ENABLE_BIT                       0x40000000
#define WINDOW_SHIFT                            19
#define WINDOW_VALUE_MASK                       0x3F
#define WINDOW_START                            MAX_UNWINDOWED_ADDRESS
#define WINDOW_RANGE_MASK                       0x7FFFF

#define QCN9224_PCIE_REMAP_BAR_CTRL_OFFSET      0x310C
#define PCIE_SOC_GLOBAL_RESET_ADDRESS 		0x3008
#define QCN9224_TCSR_SOC_HW_VERSION		0x1B00000
#define QCN9224_TCSR_SOC_HW_VERSION_MASK	GENMASK(11,8)
#define QCN9224_TCSR_SOC_HW_VERSION_SHIFT 	8
#define PCIE_SOC_GLOBAL_RESET_VALUE 		0x5
#define MAX_SOC_GLOBAL_RESET_WAIT_CNT 		50 /* x 20msec */

#define QCN9224_TCSR_PBL_LOGGING_REG		0x01B00094
#define QCN9224_SECURE_BOOT0_AUTH_EN 		0x01e24010
#define QCN9224_OEM_MODEL_ID			0x01e24018
#define QCN9224_ANTI_ROLL_BACK_FEATURE 		0x01e2401c
#define QCN9224_OEM_PK_HASH 			0x01e24060
#define QCN9224_SECURE_BOOT0_AUTH_EN_MASK 	(0x1)
#define QCN9224_OEM_ID_MASK 			GENMASK(31,16)
#define QCN9224_OEM_ID_SHIFT 			16
#define QCN9224_MODEL_ID_MASK 			GENMASK(15,0)
#define QCN9224_ANTI_ROLL_BACK_FEATURE_EN_MASK 	BIT(9)
#define QCN9224_ANTI_ROLL_BACK_FEATURE_EN_SHIFT 9
#define QCN9224_TOTAL_ROT_NUM_MASK 		GENMASK(13,12)
#define QCN9224_TOTAL_ROT_NUM_SHIFT 		12
#define QCN9224_ROT_REVOCATION_MASK 		GENMASK(17,14)
#define QCN9224_ROT_REVOCATION_SHIFT 		14
#define QCN9224_ROT_ACTIVATION_MASK 		GENMASK(21,18)
#define QCN9224_ROT_ACTIVATION_SHIFT 		18
#define QCN9224_OEM_PK_HASH_SIZE 		36
#define QCN9224_JTAG_ID				0x01e22b3c
#define QCN9224_SERIAL_NUM			0x01e22b40
#define QCN9224_PART_TYPE_EXTERNAL		0x01f94090
#define QCN9224_PART_TYPE_EXTERNAL_MASK 	BIT(3)
#define QCN9224_PART_TYPE_EXTERNAL_SHIFT 	3

#define MHICTRL (0x38)
#define BHI_STATUS (0x12C)
#define BHI_IMGADDR_LOW (0x108)
#define BHI_IMGADDR_HIGH (0x10C)
#define BHI_IMGSIZE (0x110)
#define BHI_ERRCODE (0x130)
#define BHI_ERRDBG1 (0x134)
#define BHI_ERRDBG2 (0x138)
#define BHI_ERRDBG3 (0x13C)
#define BHI_IMGTXDB (0x118)
#define BHI_EXECENV (0x128)

#define MHICTRL_RESET_MASK (0x2)
#define BHI_STATUS_MASK (0xC0000000)
#define BHI_STATUS_SHIFT (30)
#define BHI_STATUS_SUCCESS (2)

#define NO_MASK (0xFFFFFFFF)

struct jtag_ids {
	u32 id;
	char *name;
};

struct jtag_ids qcn9224_jtag_ids[] = {
	{ 0x101D50E1, "QCN9274" },
	{ 0x101D80E1, "QCN9272" },
	{ 0x101ED0E1, "QCN6214" },
	{ 0x101EE0E1, "QCN6224" },
	{ 0x101EF0E1, "QCN6274" },
};
#endif

static unsigned int local_buses[] = { 0, 0 };
struct pci_controller pci_hose[PCI_MAX_DEVICES];
extern int get_soc_version(uint32_t *soc_ver_major, uint32_t *soc_ver_minor);

#ifndef CONFIG_IPQ806X
static int phy_initialised;

struct phy_regs {
	u32 reg_offset;
	u32 val;
};

static const struct phy_regs pcie_phy_v2_x2_init_seq_ipq[] = {
	{ PCS_COM_POWER_DOWN_CONTROL + 0x800,			0x00000001},
	{ PCIE_0_QSERDES_PLL_BIAS_EN_CLKBUFLR_EN,		0x00000018},
	{ PCIE_0_QSERDES_PLL_BIAS_EN_CTRL_BY_PSM,		0x00000001},
	{ PCIE_0_QSERDES_PLL_CLK_SELECT,			0x00000031},
	{ PCIE_0_QSERDES_PLL_PLL_IVCO,				0x0000000F},
	{ PCIE_0_QSERDES_PLL_BG_TRIM,				0x0000000F},
	/* delay 5ms */
	{ PCIE_PHY_DELAY_MS,					0x00000005},
	{ PCIE_0_QSERDES_PLL_CMN_CONFIG,			0x00000006},
	{ PCIE_0_QSERDES_PLL_LOCK_CMP_EN,			0x00000042},
	{ PCIE_0_QSERDES_PLL_RESETSM_CNTRL,			0x00000020},
	{ PCIE_0_QSERDES_PLL_SVS_MODE_CLK_SEL,			0x00000001},
	{ PCIE_0_QSERDES_PLL_VCO_TUNE_MAP,			0x00000004},
	{ PCIE_0_QSERDES_PLL_SVS_MODE_CLK_SEL,			0x00000005},
	{ PCIE_0_QSERDES_PLL_VCO_TUNE_TIMER1,			0x000000FF},
	{ PCIE_0_QSERDES_PLL_VCO_TUNE_TIMER2,			0x0000003F},
	{ PCIE_0_QSERDES_PLL_CORE_CLK_EN,			0x00000030},
	{ PCIE_0_QSERDES_PLL_HSCLK_SEL,				0x00000021},
	{ PCIE_0_QSERDES_PLL_DEC_START_MODE0,			0x00000068},
	{ PCIE_0_QSERDES_PLL_DIV_FRAC_START3_MODE0,		0x00000002},
	{ PCIE_0_QSERDES_PLL_DIV_FRAC_START2_MODE0,		0x000000AA},
	{ PCIE_0_QSERDES_PLL_DIV_FRAC_START1_MODE0,		0x000000AB},
	{ PCIE_0_QSERDES_PLL_LOCK_CMP2_MODE0,			0x00000014},
	{ PCIE_0_QSERDES_PLL_LOCK_CMP1_MODE0,			0x000000D4},
	{ PCIE_0_QSERDES_PLL_CP_CTRL_MODE0,			0x00000009},
	{ PCIE_0_QSERDES_PLL_PLL_RCTRL_MODE0,			0x00000016},
	{ PCIE_0_QSERDES_PLL_PLL_CCTRL_MODE0,			0x00000028},
	{ PCIE_0_QSERDES_PLL_INTEGLOOP_GAIN1_MODE0,		0x00000000},
	{ PCIE_0_QSERDES_PLL_INTEGLOOP_GAIN0_MODE0,		0x000000A0},
	{ PCIE_0_QSERDES_PLL_VCO_TUNE2_MODE0,			0x00000002},
	{ PCIE_0_QSERDES_PLL_VCO_TUNE1_MODE0,			0x00000024},
	{ PCIE_0_QSERDES_PLL_SVS_MODE_CLK_SEL,			0x00000005},
	{ PCIE_0_QSERDES_PLL_CORE_CLK_EN,			0x00000000},
	{ PCIE_0_QSERDES_PLL_CORECLK_DIV,			0x0000000A},
	{ PCIE_0_QSERDES_PLL_CLK_SELECT,			0x00000032},
	{ PCIE_0_QSERDES_PLL_SYS_CLK_CTRL,			0x00000002},
	{ PCIE_0_QSERDES_PLL_SYSCLK_BUF_ENABLE,			0x00000007},
	{ PCIE_0_QSERDES_PLL_SYSCLK_EN_SEL,			0x00000008},
	{ PCIE_0_QSERDES_PLL_BG_TIMER,				0x0000000A},
	{ PCIE_0_QSERDES_PLL_HSCLK_SEL,				0x00000001},
	{ PCIE_0_QSERDES_PLL_DEC_START_MODE1,			0x00000053},
	{ PCIE_0_QSERDES_PLL_DIV_FRAC_START3_MODE1,		0x00000005},
	{ PCIE_0_QSERDES_PLL_DIV_FRAC_START2_MODE1,		0x00000055},
	{ PCIE_0_QSERDES_PLL_DIV_FRAC_START1_MODE1,		0x00000055},
	{ PCIE_0_QSERDES_PLL_LOCK_CMP2_MODE1,			0x00000029},
	{ PCIE_0_QSERDES_PLL_LOCK_CMP1_MODE1,			0x000000AA},
	{ PCIE_0_QSERDES_PLL_CP_CTRL_MODE1,			0x00000009},
	{ PCIE_0_QSERDES_PLL_PLL_RCTRL_MODE1,			0x00000016},
	{ PCIE_0_QSERDES_PLL_PLL_CCTRL_MODE1,			0x00000028},
	{ PCIE_0_QSERDES_PLL_INTEGLOOP_GAIN1_MODE1,		0x00000000},
	{ PCIE_0_QSERDES_PLL_INTEGLOOP_GAIN0_MODE1,		0x000000A0},
	{ PCIE_0_QSERDES_PLL_VCO_TUNE2_MODE1,			0x00000003},
	{ PCIE_0_QSERDES_PLL_VCO_TUNE1_MODE1,			0x000000B4},
	{ PCIE_0_QSERDES_PLL_SVS_MODE_CLK_SEL,			0x00000005},
	{ PCIE_0_QSERDES_PLL_CORE_CLK_EN,			0x00000000},
	{ PCIE_0_QSERDES_PLL_CORECLK_DIV_MODE1,			0x00000008},
	/* SSC init */
	{ PCIE_0_QSERDES_PLL_SSC_EN_CENTER,			0x00000001},
	{ PCIE_0_QSERDES_PLL_SSC_PER1,				0x0000007D},
	{ PCIE_0_QSERDES_PLL_SSC_PER2,				0x00000001},
	{ PCIE_0_QSERDES_PLL_SSC_ADJ_PER1,			0x00000000},
	{ PCIE_0_QSERDES_PLL_SSC_ADJ_PER2,			0x00000000},
	{ PCIE_0_QSERDES_PLL_SSC_STEP_SIZE1_MODE0,		0x0000000A},
	{ PCIE_0_QSERDES_PLL_SSC_STEP_SIZE2_MODE0,		0x00000005},
	{ PCIE_0_QSERDES_PLL_SSC_STEP_SIZE1_MODE1,		0x00000008},
	{ PCIE_0_QSERDES_PLL_SSC_STEP_SIZE2_MODE1,		0x00000004},
	/*qmp_tx_init*/
	{ PCIE_0_QSERDES_TX0_RES_CODE_LANE_OFFSET_TX,		0x00000002},
	{ PCIE_0_QSERDES_TX0_RCV_DETECT_LVL_2,			0x00000012},
	{ PCIE_0_QSERDES_TX0_HIGHZ_DRVR_EN,			0x00000010},
	{ PCIE_0_QSERDES_TX0_LANE_MODE_1,			0x00000006},
	/*qmp_rx_init*/
	{ PCIE_0_QSERDES_RX0_SIGDET_CNTRL,			0x00000003},
	{ PCIE_0_QSERDES_RX0_SIGDET_ENABLES,			0x0000001C},
	{ PCIE_0_QSERDES_RX0_SIGDET_DEGLITCH_CNTRL,		0x00000014},
	{ PCIE_0_QSERDES_RX0_RX_EQU_ADAPTOR_CNTRL2,		0x00000061},
	{ PCIE_0_QSERDES_RX0_RX_EQU_ADAPTOR_CNTRL3,		0x00000004},
	{ PCIE_0_QSERDES_RX0_RX_EQU_ADAPTOR_CNTRL4,		0x0000001E},
	{ PCIE_0_QSERDES_RX0_DFE_EN_TIMER,			0x00000004},
	{ PCIE_0_QSERDES_RX0_UCDR_FO_GAIN,			0x0000000C},
	{ PCIE_0_QSERDES_RX0_UCDR_SO_GAIN,			0x00000002},
	{ PCIE_0_QSERDES_RX0_UCDR_SO_SATURATION_AND_ENABLE,	0x0000007F},
	{ PCIE_0_QSERDES_RX0_UCDR_PI_CONTROLS,			0x00000070},
	{ PCIE_0_QSERDES_RX0_RX_EQ_OFFSET_ADAPTOR_CNTRL1,	0x00000073},
	{ PCIE_0_QSERDES_RX0_RX_OFFSET_ADAPTOR_CNTRL2,		0x00000080},
	{ PCIE_0_QSERDES_RX0_RX_MODE_10_LOW,			0x00000000},
	{ PCIE_0_QSERDES_RX0_RX_MODE_10_HIGH,			0x00000002},
	{ PCIE_0_QSERDES_RX0_RX_MODE_10_HIGH2,			0x000000C8},
	{ PCIE_0_QSERDES_RX0_RX_MODE_10_HIGH3,			0x00000009},
	{ PCIE_0_QSERDES_RX0_RX_MODE_10_HIGH4,			0x000000B1},
	{ PCIE_0_QSERDES_RX0_RX_MODE_01_LOW,			0x00000000},
	{ PCIE_0_QSERDES_RX0_RX_MODE_01_HIGH,			0x00000002},
	{ PCIE_0_QSERDES_RX0_RX_MODE_01_HIGH2,			0x000000C8},
	{ PCIE_0_QSERDES_RX0_RX_MODE_01_HIGH3,			0x00000009},
	{ PCIE_0_QSERDES_RX0_RX_MODE_01_HIGH4,			0x000000B1},
	{ PCIE_0_QSERDES_RX0_RX_MODE_00_LOW,			0x000000F0},
	{ PCIE_0_QSERDES_RX0_RX_MODE_00_HIGH,			0x00000002},
	{ PCIE_0_QSERDES_RX0_RX_MODE_00_HIGH2,			0x0000002F},
	{ PCIE_0_QSERDES_RX0_RX_MODE_00_HIGH3,			0x000000D3},
	{ PCIE_0_QSERDES_RX0_RX_MODE_00_HIGH4,			0x00000040},
	{ PCIE_0_QSERDES_RX0_RX_IDAC_TSETTLE_HIGH,		0x00000000},
	{ PCIE_0_QSERDES_RX0_RX_IDAC_TSETTLE_LOW,		0x000000C0},
	/* TX1 & RX1 */
	{ PCIE_0_QSERDES_TX1_RES_CODE_LANE_OFFSET_TX,		0x00000002},
	{ PCIE_0_QSERDES_TX1_RCV_DETECT_LVL_2	,		0x00000012},
	{ PCIE_0_QSERDES_TX1_HIGHZ_DRVR_EN	,		0x00000010},
	{ PCIE_0_QSERDES_TX1_LANE_MODE_1,			0x00000006},
	{ PCIE_0_QSERDES_RX1_SIGDET_CNTRL,			0x00000003},
	{ PCIE_0_QSERDES_RX1_SIGDET_ENABLES,			0x0000001C},
	{ PCIE_0_QSERDES_RX1_SIGDET_DEGLITCH_CNTRL,		0x00000014},
	{ PCIE_0_QSERDES_RX1_RX_EQU_ADAPTOR_CNTRL2,		0x00000061},
	{ PCIE_0_QSERDES_RX1_RX_EQU_ADAPTOR_CNTRL3,		0x00000004},
	{ PCIE_0_QSERDES_RX1_RX_EQU_ADAPTOR_CNTRL4,		0x0000001E},
	{ PCIE_0_QSERDES_RX1_DFE_EN_TIMER,			0x00000004},
	{ PCIE_0_QSERDES_RX1_UCDR_FO_GAIN,			0x0000000C},
	{ PCIE_0_QSERDES_RX1_UCDR_SO_GAIN,			0x00000002},
	{ PCIE_0_QSERDES_RX1_UCDR_SO_SATURATION_AND_ENABLE,	0x0000007F},
	{ PCIE_0_QSERDES_RX1_UCDR_PI_CONTROLS,			0x00000070},
	{ PCIE_0_QSERDES_RX1_RX_EQ_OFFSET_ADAPTOR_CNTRL1,	0x00000073},
	{ PCIE_0_QSERDES_RX1_RX_OFFSET_ADAPTOR_CNTRL2,		0x00000080},
	{ PCIE_0_QSERDES_RX1_RX_MODE_10_LOW,			0x00000000},
	{ PCIE_0_QSERDES_RX1_RX_MODE_10_HIGH,			0x00000002},
	{ PCIE_0_QSERDES_RX1_RX_MODE_10_HIGH2,			0x000000C8},
	{ PCIE_0_QSERDES_RX1_RX_MODE_10_HIGH3,			0x00000009},
	{ PCIE_0_QSERDES_RX1_RX_MODE_10_HIGH4,			0x000000B1},
	{ PCIE_0_QSERDES_RX1_RX_MODE_01_LOW,			0x00000000},
	{ PCIE_0_QSERDES_RX1_RX_MODE_01_HIGH,			0x00000002},
	{ PCIE_0_QSERDES_RX1_RX_MODE_01_HIGH2,			0x000000C8},
	{ PCIE_0_QSERDES_RX1_RX_MODE_01_HIGH3,			0x00000009},
	{ PCIE_0_QSERDES_RX1_RX_MODE_01_HIGH4,			0x000000B1},
	{ PCIE_0_QSERDES_RX1_RX_MODE_00_LOW,			0x000000F0},
	{ PCIE_0_QSERDES_RX1_RX_MODE_00_HIGH,			0x00000002},
	{ PCIE_0_QSERDES_RX1_RX_MODE_00_HIGH2,			0x0000002F},
	{ PCIE_0_QSERDES_RX1_RX_MODE_00_HIGH3,			0x000000D3},
	{ PCIE_0_QSERDES_RX1_RX_MODE_00_HIGH4,			0x00000040},
	{ PCIE_0_QSERDES_RX1_RX_IDAC_TSETTLE_HIGH,		0x00000000},
	{ PCIE_0_QSERDES_RX1_RX_IDAC_TSETTLE_LOW,		0x000000C0},
	{ PCIE_0_PCS_COM_REFGEN_REQ_CONFIG1 + 0x800,		0x0000000D},
	{ PCIE_0_PCS_COM_G12S1_TXDEEMPH_M3P5DB + 0x800,		0x00000010},
	{ PCIE_0_PCS_COM_P2U3_WAKEUP_DLY_TIME_AUXCLK_H + 0x800, 0x00000000},
	{ PCIE_0_PCS_COM_P2U3_WAKEUP_DLY_TIME_AUXCLK_L + 0x800, 0x00000001},
	{ PCIE_0_PCS_PCIE_OSC_DTCT_ACTIONS + 0x804,		0x00000000},
	{ PCIE_0_PCS_PCIE_POWER_STATE_CONFIG2 + 0x800,		0x0000001D},
	{ PCIE_0_PCS_PCIE_L1P1_WAKEUP_DLY_TIME_AUXCLK_H + 0x804,0x00000000},
	{ PCIE_0_PCS_PCIE_L1P1_WAKEUP_DLY_TIME_AUXCLK_L + 0x804,0x00000001},
	{ PCIE_0_PCS_PCIE_L1P2_WAKEUP_DLY_TIME_AUXCLK_H + 0x804,0x00000000},
	{ PCIE_0_PCS_PCIE_L1P2_WAKEUP_DLY_TIME_AUXCLK_L + 0x804,0x00000001},
	{ PCIE_0_PCS_PCIE_EQ_CONFIG1 + 0x804,			0x00000014},
	{ PCIE_0_PCS_PCIE_EQ_CONFIG1 + 0x804,			0x00000010},
	{ PCIE_0_PCS_PCIE_EQ_CONFIG2 + 0x804,			0x0000000B},
	{ PCIE_0_PCS_PCIE_PRESET_P10_PRE + 0x804,		0x00000000},
	{ PCIE_0_PCS_PCIE_PRESET_P10_POST + 0x804,		0x00000058},
	{ PCIE_0_PCS_PCIE_POWER_STATE_CONFIG4 + 0x800,		0x00000007},
	{ PCIE_0_PCS_PCIE_OSC_DTCT_CONFIG1 + 0x804,		0x00000000},
	{ PCIE_0_PCS_PCIE_OSC_DTCT_CONFIG2 + 0x804,		0x00000052},
	{ PCIE_0_PCS_PCIE_OSC_DTCT_CONFIG4 + 0x804,		0x00000019},
	{ PCIE_0_PCS_PCIE_INT_AUX_CLK_CONFIG1 + 0x804,		0x00000000},
	{ PCIE_0_PCS_PCIE_OSC_DTCT_MODE2_CONFIG2 + 0x804,	0x00000049},
	{ PCIE_0_PCS_PCIE_OSC_DTCT_MODE2_CONFIG4 + 0x804,	0x0000002A},
	{ PCIE_0_PCS_PCIE_OSC_DTCT_MODE2_CONFIG5 + 0x804,	0x00000002},
	{ PCIE_0_PCS_PCIE_OSC_DTCT_MODE2_CONFIG6 + 0x804,	0x00000003},
	{ PCIE_0_QSERDES_PLL_CLK_EP_DIV_MODE0,			0x00000019},
	{ PCIE_0_QSERDES_PLL_CLK_EP_DIV_MODE1,			0x00000028},
	{ PCIE_0_QSERDES_PLL_CLK_ENABLE1,			0x00000090},
	{ PCIE_0_QSERDES_PLL_HSCLK_SEL,				0x00000089},
	{ PCIE_0_QSERDES_PLL_CLK_ENABLE1,			0x00000010},
	{ PCIE_0_PCS_COM_POWER_DOWN_CONTROL + 0x800,		0x00000003},
	{ PCIE_0_PCS_PCIE_ENDPOINT_REFCLK_DRIVE + 0x804,	0x000000C1},
	{ PCIE_0_PCS_COM_RX_DCC_CAL_CONFIG + 0x800,		0x00000001},
	{ PCIE_0_PCS_COM_RX_SIGDET_LVL + 0x800,			0x000000AA},
	{ PCIE_0_PCS_COM_SW_RESET + 0x800,			0x00000000},
	{ PCIE_0_PCS_COM_START_CONTROL + 0x800,			0x00000002},
	{ PCIE_0_PCS_COM_START_CONTROL + 0x800,			0x00000003},
};

static const struct phy_regs pcie_phy_v2_init_seq_ipq[] = {
#if defined(CONFIG_IPQ807x)
	{ PCS_COM_POWER_DOWN_CONTROL,				0x00000001},
	{ PCIE_0_QSERDES_PLL_BIAS_EN_CLKBUFLR_EN,		0x00000018},
	{ PCIE_0_QSERDES_PLL_BIAS_EN_CTRL_BY_PSM,		0x00000001},
	{ PCIE_0_QSERDES_PLL_CLK_SELECT,			0x00000031},
	{ PCIE_0_QSERDES_PLL_PLL_IVCO,				0x0000000F},
	{ PCIE_0_QSERDES_PLL_BG_TRIM,				0x0000000F},
	/* delay 5ms */
	{ PCIE_PHY_DELAY_MS,					0x00000005},
	{ PCIE_0_QSERDES_PLL_CMN_CONFIG,			0x00000006},
	{ PCIE_0_QSERDES_PLL_LOCK_CMP_EN,			0x00000042},
	{ PCIE_0_QSERDES_PLL_RESETSM_CNTRL,			0x00000020},
	{ PCIE_0_QSERDES_PLL_SVS_MODE_CLK_SEL,			0x00000001},
	{ PCIE_0_QSERDES_PLL_VCO_TUNE_MAP,			0x00000004},
	{ PCIE_0_QSERDES_PLL_SVS_MODE_CLK_SEL,			0x00000005},
	{ PCIE_0_QSERDES_PLL_VCO_TUNE_TIMER1,			0x000000FF},
	{ PCIE_0_QSERDES_PLL_VCO_TUNE_TIMER2,			0x0000003F},
	{ PCIE_0_QSERDES_PLL_CORE_CLK_EN,			0x00000030},
	{ PCIE_0_QSERDES_PLL_HSCLK_SEL,				0x00000021},
	{ PCIE_0_QSERDES_PLL_DEC_START_MODE0,			0x00000082},
	{ PCIE_0_QSERDES_PLL_DIV_FRAC_START3_MODE0,		0x00000003},
	{ PCIE_0_QSERDES_PLL_DIV_FRAC_START2_MODE0,		0x00000355},
	{ PCIE_0_QSERDES_PLL_DIV_FRAC_START1_MODE0,		0x00035555},
	{ PCIE_0_QSERDES_PLL_LOCK_CMP2_MODE0,			0x0000001A},
	{ PCIE_0_QSERDES_PLL_LOCK_CMP1_MODE0,			0x00001A0A},
	{ PCIE_0_QSERDES_PLL_CP_CTRL_MODE0,			0x0000000B},
	{ PCIE_0_QSERDES_PLL_PLL_RCTRL_MODE0,			0x00000016},
	{ PCIE_0_QSERDES_PLL_PLL_CCTRL_MODE0,			0x00000028},
	{ PCIE_0_QSERDES_PLL_INTEGLOOP_GAIN1_MODE0,		0x00000000},
	{ PCIE_0_QSERDES_PLL_INTEGLOOP_GAIN0_MODE0,		0x00000040},
	{ PCIE_0_QSERDES_PLL_VCO_TUNE2_MODE0,			0x00000002},
	{ PCIE_0_QSERDES_PLL_VCO_TUNE1_MODE0,			0x00000024},
	{ PCIE_0_QSERDES_PLL_SVS_MODE_CLK_SEL,			0x00000005},
	{ PCIE_0_QSERDES_PLL_CORE_CLK_EN,			0x00000020},
	{ PCIE_0_QSERDES_PLL_CORECLK_DIV,			0x0000000A},
	{ PCIE_0_QSERDES_PLL_CLK_SELECT,			0x00000032},
	{ PCIE_0_QSERDES_PLL_SYS_CLK_CTRL,			0x00000002},
	{ PCIE_0_QSERDES_PLL_SYSCLK_BUF_ENABLE,			0x00000007},
	{ PCIE_0_QSERDES_PLL_SYSCLK_EN_SEL,			0x00000008},
	{ PCIE_0_QSERDES_PLL_BG_TIMER,				0x0000000A},
	{ PCIE_0_QSERDES_PLL_HSCLK_SEL,				0x00000001},
	{ PCIE_0_QSERDES_PLL_DEC_START_MODE1,			0x00000068},
	{ PCIE_0_QSERDES_PLL_DIV_FRAC_START3_MODE1,		0x00000002},
	{ PCIE_0_QSERDES_PLL_DIV_FRAC_START2_MODE1,		0x000002AA},
	{ PCIE_0_QSERDES_PLL_DIV_FRAC_START1_MODE1,		0x0002AAAB},
	{ PCIE_0_QSERDES_PLL_LOCK_CMP2_MODE1,			0x00000034},
	{ PCIE_0_QSERDES_PLL_LOCK_CMP1_MODE1,			0x00003414},
	{ PCIE_0_QSERDES_PLL_CP_CTRL_MODE1,			0x0000000B},
	{ PCIE_0_QSERDES_PLL_PLL_RCTRL_MODE1,			0x00000016},
	{ PCIE_0_QSERDES_PLL_PLL_CCTRL_MODE1,			0x00000028},
	{ PCIE_0_QSERDES_PLL_INTEGLOOP_GAIN1_MODE1,		0x00000000},
	{ PCIE_0_QSERDES_PLL_INTEGLOOP_GAIN0_MODE1,		0x00000040},
	{ PCIE_0_QSERDES_PLL_VCO_TUNE2_MODE1,			0x00000003},
	{ PCIE_0_QSERDES_PLL_VCO_TUNE1_MODE1,			0x000000B4},
	{ PCIE_0_QSERDES_PLL_SVS_MODE_CLK_SEL,			0x00000005},
	{ PCIE_0_QSERDES_PLL_CORE_CLK_EN,			0x00000000},
	{ PCIE_0_QSERDES_PLL_CORECLK_DIV_MODE1,			0x00000008},
	/*qmp_tx_init*/
	{ PCIE_0_QSERDES_TX0_RES_CODE_LANE_OFFSET_TX,		0x00000002},
	{ PCIE_0_QSERDES_TX0_RCV_DETECT_LVL_2,			0x00000012},
	{ PCIE_0_QSERDES_TX0_HIGHZ_DRVR_EN,			0x00000010},
	{ PCIE_0_QSERDES_TX0_LANE_MODE_1,			0x00000006},
	/*qmp_rx_init*/
	{ PCIE_0_QSERDES_RX0_SIGDET_CNTRL,			0x00000003},
	{ PCIE_0_QSERDES_RX0_SIGDET_ENABLES,			0x0000001C},
	{ PCIE_0_QSERDES_RX0_SIGDET_DEGLITCH_CNTRL,		0x00000014},
	{ PCIE_0_QSERDES_RX0_RX_EQU_ADAPTOR_CNTRL2,		0x0000000E},
	{ PCIE_0_QSERDES_RX0_RX_EQU_ADAPTOR_CNTRL3,		0x00000004},
	{ PCIE_0_QSERDES_RX0_RX_EQU_ADAPTOR_CNTRL4,		0x0000001B},
	{ PCIE_0_QSERDES_RX0_DFE_EN_TIMER,			0x00000004},
	{ PCIE_0_QSERDES_RX0_UCDR_SO_SATURATION_AND_ENABLE,	0x0000007F},
	{ PCIE_0_QSERDES_RX0_UCDR_PI_CONTROLS,			0x00000070},
	{ PCIE_0_QSERDES_RX0_RX_EQ_OFFSET_ADAPTOR_CNTRL1,	0x00000073},
	{ PCIE_0_QSERDES_RX0_RX_OFFSET_ADAPTOR_CNTRL2,		0x00000080},
	{ PCIE_0_QSERDES_RX0_RX_MODE_10_LOW,			0x00000000},
	{ PCIE_0_QSERDES_RX0_RX_MODE_10_HIGH,			0x00000002},
	{ PCIE_0_QSERDES_RX0_RX_MODE_10_HIGH2,			0x000000C8},
	{ PCIE_0_QSERDES_RX0_RX_MODE_10_HIGH3,			0x00000009},
	{ PCIE_0_QSERDES_RX0_RX_MODE_10_HIGH4,			0x000000B1},
	{ PCIE_0_QSERDES_RX0_RX_MODE_01_LOW,			0x00000000},
	{ PCIE_0_QSERDES_RX0_RX_MODE_01_HIGH,			0x00000002},
	{ PCIE_0_QSERDES_RX0_RX_MODE_01_HIGH2,			0x000000C8},
	{ PCIE_0_QSERDES_RX0_RX_MODE_01_HIGH3,			0x00000009},
	{ PCIE_0_QSERDES_RX0_RX_MODE_01_HIGH4,			0x000000B1},
	{ PCIE_0_QSERDES_RX0_RX_MODE_00_LOW,			0x000000F0},
	{ PCIE_0_QSERDES_RX0_RX_MODE_00_HIGH,			0x00000002},
	{ PCIE_0_QSERDES_RX0_RX_MODE_00_HIGH2,			0x0000002F},
	{ PCIE_0_QSERDES_RX0_RX_MODE_00_HIGH3,			0x000000D3},
	{ PCIE_0_QSERDES_RX0_RX_MODE_00_HIGH4,			0x00000040},
	{ PCIE_0_QSERDES_RX0_RX_IDAC_TSETTLE_HIGH,		0x00000000},
	{ PCIE_0_QSERDES_RX0_RX_IDAC_TSETTLE_LOW,		0x000000C0},
	/* pcie fll config*/
	{ PCIE_0_PCS_COM_FLL_CNTRL2,				0x00000083},
	{ PCIE_0_PCS_COM_FLL_CNT_VAL_L,				0x00000009},
	{ PCIE_0_PCS_COM_FLL_CNT_VAL_H_TOL,			0x000000A2},
	{ PCIE_0_PCS_COM_FLL_MAN_CODE,				0x00000040},
	{ PCIE_0_PCS_COM_FLL_CNTRL1,				0x00000001},
	{ PCIE_0_PCS_COM_P2U3_WAKEUP_DLY_TIME_AUXCLK_H, 	0x00000000},
	{ PCIE_0_PCS_COM_P2U3_WAKEUP_DLY_TIME_AUXCLK_L, 	0x00000001},
	{ PCIE_0_PCS_PCIE_OSC_DTCT_ACTIONS,			0x00000000},
	{ PCIE_0_PCS_PCIE_L1P1_WAKEUP_DLY_TIME_AUXCLK_H,	0x00000000},
	{ PCIE_0_PCS_PCIE_L1P1_WAKEUP_DLY_TIME_AUXCLK_L,	0x00000001},
	{ PCIE_0_PCS_PCIE_L1P2_WAKEUP_DLY_TIME_AUXCLK_H,	0x00000000},
	{ PCIE_0_PCS_PCIE_L1P2_WAKEUP_DLY_TIME_AUXCLK_L,	0x00000001},
	{ PCIE_0_PCS_PCIE_EQ_CONFIG1,				0x00000011},
	{ PCIE_0_PCS_PCIE_EQ_CONFIG2,				0x0000000B},
	{ PCIE_0_PCS_PCIE_POWER_STATE_CONFIG4,			0x00000007},
	{ PCIE_0_PCS_PCIE_OSC_DTCT_CONFIG2,			0x00000052},
	{ PCIE_0_PCS_PCIE_OSC_DTCT_MODE2_CONFIG2,		0x00000050},
	{ PCIE_0_PCS_PCIE_OSC_DTCT_MODE2_CONFIG4,		0x0000001A},
	{ PCIE_0_PCS_PCIE_OSC_DTCT_MODE2_CONFIG5,		0x00000006},
	{ PCIE_0_QSERDES_PLL_CLK_EP_DIV_MODE0,			0x00000019},
	{ PCIE_0_QSERDES_PLL_CLK_EP_DIV_MODE1,			0x00000028},
	{ PCIE_0_QSERDES_PLL_CLK_ENABLE1,			0x00000090},
	{ PCIE_0_PCS_COM_POWER_DOWN_CONTROL,			0x00000003},
	{ PCIE_0_PCS_PCIE_ENDPOINT_REFCLK_DRIVE,		0x000000C1},
	{ PCIE_0_PCS_COM_RX_DCC_CAL_CONFIG,			0x00000001},
	{ PCIE_0_PCS_COM_RX_SIGDET_LVL,				0x000000AA},
	{ PCIE_0_PCS_COM_REFGEN_REQ_CONFIG1,			0x0000000D},
	{ PCIE_0_PCS_COM_SW_RESET,				0x00000000},
	{ PCIE_0_PCS_COM_START_CONTROL,				0x00000003},
#elif defined(CONFIG_IPQ9574)
	{ PCS_COM_POWER_DOWN_CONTROL,				0x00000001},
	{ PCIE_0_QSERDES_PLL_BIAS_EN_CLKBUFLR_EN,		0x00000018},
	{ PCIE_0_QSERDES_PLL_BIAS_EN_CTRL_BY_PSM,		0x00000001},
	{ PCIE_0_QSERDES_PLL_CLK_SELECT,			0x00000031},
	{ PCIE_0_QSERDES_PLL_PLL_IVCO,				0x0000000F},
	{ PCIE_0_QSERDES_PLL_BG_TRIM,				0x0000000F},
	/* delay 5ms */
	{ PCIE_PHY_DELAY_MS,					0x00000005},
	{ PCIE_0_QSERDES_PLL_CMN_CONFIG,			0x00000006},
	{ PCIE_0_QSERDES_PLL_LOCK_CMP_EN,			0x00000042},
	{ PCIE_0_QSERDES_PLL_RESETSM_CNTRL,			0x00000020},
	{ PCIE_0_QSERDES_PLL_SVS_MODE_CLK_SEL,			0x00000001},
	{ PCIE_0_QSERDES_PLL_VCO_TUNE_MAP,			0x00000004},
	{ PCIE_0_QSERDES_PLL_SVS_MODE_CLK_SEL,			0x00000005},
	{ PCIE_0_QSERDES_PLL_VCO_TUNE_TIMER1,			0x000000FF},
	{ PCIE_0_QSERDES_PLL_VCO_TUNE_TIMER2,			0x0000003F},
	{ PCIE_0_QSERDES_PLL_CORE_CLK_EN,			0x00000030},
	{ PCIE_0_QSERDES_PLL_HSCLK_SEL,				0x00000021},
	{ PCIE_0_QSERDES_PLL_DEC_START_MODE0,			0x00000068},
	{ PCIE_0_QSERDES_PLL_DIV_FRAC_START3_MODE0,		0x00000002},
	{ PCIE_0_QSERDES_PLL_DIV_FRAC_START2_MODE0,		0x000000AA},
	{ PCIE_0_QSERDES_PLL_DIV_FRAC_START1_MODE0,		0x000000AB},
	{ PCIE_0_QSERDES_PLL_LOCK_CMP2_MODE0,			0x00000014},
	{ PCIE_0_QSERDES_PLL_LOCK_CMP1_MODE0,			0x000000D4},
	{ PCIE_0_QSERDES_PLL_CP_CTRL_MODE0,			0x00000009},
	{ PCIE_0_QSERDES_PLL_PLL_RCTRL_MODE0,			0x00000016},
	{ PCIE_0_QSERDES_PLL_PLL_CCTRL_MODE0,			0x00000028},
	{ PCIE_0_QSERDES_PLL_INTEGLOOP_GAIN1_MODE0,		0x00000000},
	{ PCIE_0_QSERDES_PLL_INTEGLOOP_GAIN0_MODE0,		0x000000A0},
	{ PCIE_0_QSERDES_PLL_VCO_TUNE2_MODE0,			0x00000002},
	{ PCIE_0_QSERDES_PLL_VCO_TUNE1_MODE0,			0x00000024},
	{ PCIE_0_QSERDES_PLL_SVS_MODE_CLK_SEL,			0x00000005},
	{ PCIE_0_QSERDES_PLL_CORE_CLK_EN,			0x00000020},
	{ PCIE_0_QSERDES_PLL_CORECLK_DIV,			0x0000000A},
	{ PCIE_0_QSERDES_PLL_CLK_SELECT,			0x00000032},
	{ PCIE_0_QSERDES_PLL_SYS_CLK_CTRL,			0x00000002},
	{ PCIE_0_QSERDES_PLL_SYSCLK_BUF_ENABLE,			0x00000007},
	{ PCIE_0_QSERDES_PLL_SYSCLK_EN_SEL,			0x00000008},
	{ PCIE_0_QSERDES_PLL_BG_TIMER,				0x0000000A},
	{ PCIE_0_QSERDES_PLL_HSCLK_SEL,				0x00000001},
	{ PCIE_0_QSERDES_PLL_DEC_START_MODE1,			0x00000053},
	{ PCIE_0_QSERDES_PLL_DIV_FRAC_START3_MODE1,		0x00000005},
	{ PCIE_0_QSERDES_PLL_DIV_FRAC_START2_MODE1,		0x00000055},
	{ PCIE_0_QSERDES_PLL_DIV_FRAC_START1_MODE1,		0x00000055},
	{ PCIE_0_QSERDES_PLL_LOCK_CMP2_MODE1,			0x00000029},
	{ PCIE_0_QSERDES_PLL_LOCK_CMP1_MODE1,			0x000000AA},
	{ PCIE_0_QSERDES_PLL_CP_CTRL_MODE1,			0x00000009},
	{ PCIE_0_QSERDES_PLL_PLL_RCTRL_MODE1,			0x00000016},
	{ PCIE_0_QSERDES_PLL_PLL_CCTRL_MODE1,			0x00000028},
	{ PCIE_0_QSERDES_PLL_INTEGLOOP_GAIN1_MODE1,		0x00000000},
	{ PCIE_0_QSERDES_PLL_INTEGLOOP_GAIN0_MODE1,		0x000000A0},
	{ PCIE_0_QSERDES_PLL_VCO_TUNE2_MODE1,			0x00000003},
	{ PCIE_0_QSERDES_PLL_VCO_TUNE1_MODE1,			0x000000B4},
	{ PCIE_0_QSERDES_PLL_SVS_MODE_CLK_SEL,			0x00000005},
	{ PCIE_0_QSERDES_PLL_CORE_CLK_EN,			0x00000000},
	{ PCIE_0_QSERDES_PLL_CORECLK_DIV_MODE1,			0x00000008},
	/* SSC init */
	{ PCIE_0_QSERDES_PLL_SSC_EN_CENTER,			0x00000001},
	{ PCIE_0_QSERDES_PLL_SSC_PER1,				0x0000007D},
	{ PCIE_0_QSERDES_PLL_SSC_PER2,				0x00000001},
	{ PCIE_0_QSERDES_PLL_SSC_ADJ_PER1,			0x00000000},
	{ PCIE_0_QSERDES_PLL_SSC_ADJ_PER2,			0x00000000},
	{ PCIE_0_QSERDES_PLL_SSC_STEP_SIZE1_MODE0,		0x0000000A},
	{ PCIE_0_QSERDES_PLL_SSC_STEP_SIZE2_MODE0,		0x00000005},
	{ PCIE_0_QSERDES_PLL_SSC_STEP_SIZE1_MODE1,		0x00000008},
	{ PCIE_0_QSERDES_PLL_SSC_STEP_SIZE2_MODE1,		0x00000004},
	/*qmp_tx_init*/
	{ PCIE_0_QSERDES_TX0_RES_CODE_LANE_OFFSET_TX,		0x00000002},
	{ PCIE_0_QSERDES_TX0_RCV_DETECT_LVL_2,			0x00000012},
	{ PCIE_0_QSERDES_TX0_HIGHZ_DRVR_EN,			0x00000010},
	{ PCIE_0_QSERDES_TX0_LANE_MODE_1,			0x00000006},
	/*qmp_rx_init*/
	{ PCIE_0_QSERDES_RX0_SIGDET_CNTRL,			0x00000003},
	{ PCIE_0_QSERDES_RX0_SIGDET_ENABLES,			0x0000001C},
	{ PCIE_0_QSERDES_RX0_SIGDET_DEGLITCH_CNTRL,		0x00000014},
	{ PCIE_0_QSERDES_RX0_RX_EQU_ADAPTOR_CNTRL2,		0x00000061},
	{ PCIE_0_QSERDES_RX0_RX_EQU_ADAPTOR_CNTRL3,		0x00000004},
	{ PCIE_0_QSERDES_RX0_RX_EQU_ADAPTOR_CNTRL4,		0x0000001E},
	{ PCIE_0_QSERDES_RX0_DFE_EN_TIMER,			0x00000004},
	{ PCIE_0_QSERDES_RX0_UCDR_FO_GAIN,			0x0000000C},
	{ PCIE_0_QSERDES_RX0_UCDR_SO_GAIN,			0x00000002},
	{ PCIE_0_QSERDES_RX0_UCDR_SO_SATURATION_AND_ENABLE,	0x0000007F},
	{ PCIE_0_QSERDES_RX0_UCDR_PI_CONTROLS,			0x00000070},
	{ PCIE_0_QSERDES_RX0_RX_EQ_OFFSET_ADAPTOR_CNTRL1,	0x00000073},
	{ PCIE_0_QSERDES_RX0_RX_OFFSET_ADAPTOR_CNTRL2,		0x00000080},
	{ PCIE_0_QSERDES_RX0_RX_MODE_10_LOW,			0x00000000},
	{ PCIE_0_QSERDES_RX0_RX_MODE_10_HIGH,			0x00000002},
	{ PCIE_0_QSERDES_RX0_RX_MODE_10_HIGH2,			0x000000C8},
	{ PCIE_0_QSERDES_RX0_RX_MODE_10_HIGH3,			0x00000009},
	{ PCIE_0_QSERDES_RX0_RX_MODE_10_HIGH4,			0x000000B1},
	{ PCIE_0_QSERDES_RX0_RX_MODE_01_LOW,			0x00000000},
	{ PCIE_0_QSERDES_RX0_RX_MODE_01_HIGH,			0x00000002},
	{ PCIE_0_QSERDES_RX0_RX_MODE_01_HIGH2,			0x000000C8},
	{ PCIE_0_QSERDES_RX0_RX_MODE_01_HIGH3,			0x00000009},
	{ PCIE_0_QSERDES_RX0_RX_MODE_01_HIGH4,			0x000000B1},
	{ PCIE_0_QSERDES_RX0_RX_MODE_00_LOW,			0x000000F0},
	{ PCIE_0_QSERDES_RX0_RX_MODE_00_HIGH,			0x00000002},
	{ PCIE_0_QSERDES_RX0_RX_MODE_00_HIGH2,			0x0000002F},
	{ PCIE_0_QSERDES_RX0_RX_MODE_00_HIGH3,			0x000000D3},
	{ PCIE_0_QSERDES_RX0_RX_MODE_00_HIGH4,			0x00000040},
	{ PCIE_0_QSERDES_RX0_RX_IDAC_TSETTLE_HIGH,		0x00000000},
	{ PCIE_0_QSERDES_RX0_RX_IDAC_TSETTLE_LOW,		0x000000C0},
	{ PCIE_0_PCS_COM_P2U3_WAKEUP_DLY_TIME_AUXCLK_H, 	0x00000000},
	{ PCIE_0_PCS_COM_P2U3_WAKEUP_DLY_TIME_AUXCLK_L, 	0x00000001},
	{ PCIE_0_PCS_PCIE_OSC_DTCT_ACTIONS,			0x00000000},
	{ PCIE_0_PCS_PCIE_POWER_STATE_CONFIG2,			0x0000000D},
	{ PCIE_0_PCS_PCIE_L1P1_WAKEUP_DLY_TIME_AUXCLK_H,	0x00000000},
	{ PCIE_0_PCS_PCIE_L1P1_WAKEUP_DLY_TIME_AUXCLK_L,	0x00000001},
	{ PCIE_0_PCS_PCIE_L1P2_WAKEUP_DLY_TIME_AUXCLK_H,	0x00000000},
	{ PCIE_0_PCS_PCIE_L1P2_WAKEUP_DLY_TIME_AUXCLK_L,	0x00000001},
	{ PCIE_0_PCS_PCIE_EQ_CONFIG1,				0x00000014},
	{ PCIE_0_PCS_PCIE_EQ_CONFIG1,				0x00000010},
	{ PCIE_0_PCS_PCIE_EQ_CONFIG2,				0x0000000B},
	{ PCIE_0_PCS_PCIE_PRESET_P10_PRE,			0x00000000},
	{ PCIE_0_PCS_PCIE_PRESET_P10_POST,			0x00000058},
	{ PCIE_0_PCS_PCIE_POWER_STATE_CONFIG4,			0x00000007},
	{ PCIE_0_PCS_PCIE_OSC_DTCT_CONFIG2,			0x00000052},
	{ PCIE_0_PCS_PCIE_INT_AUX_CLK_CONFIG1,			0x00000000},
	{ PCIE_0_PCS_PCIE_OSC_DTCT_MODE2_CONFIG2,		0x00000050},
	{ PCIE_0_PCS_PCIE_OSC_DTCT_MODE2_CONFIG4,		0x0000001A},
	{ PCIE_0_PCS_PCIE_OSC_DTCT_MODE2_CONFIG5,		0x00000006},
	{ PCIE_0_PCS_PCIE_OSC_DTCT_MODE2_CONFIG6,		0x00000003},
	{ PCIE_0_QSERDES_PLL_CLK_EP_DIV_MODE0,			0x00000019},
	{ PCIE_0_QSERDES_PLL_CLK_EP_DIV_MODE1,			0x00000028},
	{ PCIE_0_QSERDES_PLL_CLK_ENABLE1,			0x00000090},
	{ PCIE_0_QSERDES_PLL_HSCLK_SEL,				0x00000089},
	{ PCIE_0_QSERDES_PLL_CLK_ENABLE1,			0x00000010},
	{ PCIE_0_PCS_COM_POWER_DOWN_CONTROL,			0x00000003},
	{ PCIE_0_PCS_PCIE_ENDPOINT_REFCLK_DRIVE,		0x000000C1},
	{ PCIE_0_PCS_COM_RX_DCC_CAL_CONFIG,			0x00000001},
	{ PCIE_0_PCS_COM_RX_SIGDET_LVL,				0x000000AA},
	{ PCIE_0_PCS_COM_REFGEN_REQ_CONFIG1,			0x0000000D},
	{ PCIE_0_PCS_COM_G12S1_TXDEEMPH_M3P5DB,			0x00000010},
	{ PCIE_0_PCS_COM_SW_RESET,				0x00000000},
	{ PCIE_0_PCS_COM_START_CONTROL,				0x00000002},
	{ PCIE_0_PCS_COM_START_CONTROL,				0x00000003},
#elif defined(CONFIG_IPQ6018)
	{ PCIE_0_PCS_COM_POWER_DOWN_CONTROL,			0x03 },
	{ PCIE_0_QSERDES_PLL_SSC_PER1,				0x7D },
	{ PCIE_0_QSERDES_PLL_SSC_PER2,				0x01 },
	{ PCIE_0_QSERDES_PLL_SSC_STEP_SIZE1_MODE0,		0x0A },
	{ PCIE_0_QSERDES_PLL_SSC_STEP_SIZE2_MODE0,		0x05 },
	{ PCIE_0_QSERDES_PLL_SSC_STEP_SIZE1_MODE1,		0x08 },
	{ PCIE_0_QSERDES_PLL_SSC_STEP_SIZE2_MODE1,		0x04 },
	{ PCIE_0_QSERDES_PLL_BIAS_EN_CLKBUFLR_EN,		0x18 },
	{ PCIE_0_QSERDES_PLL_CLK_ENABLE1,			0x90 },
	{ PCIE_0_QSERDES_PLL_SYS_CLK_CTRL,			0x02 },
	{ PCIE_0_QSERDES_PLL_SYSCLK_BUF_ENABLE,			0x07 },
	{ PCIE_0_QSERDES_PLL_PLL_IVCO,				0x0F },
	{ PCIE_0_QSERDES_PLL_LOCK_CMP1_MODE0,			0xD4 },
	{ PCIE_0_QSERDES_PLL_LOCK_CMP2_MODE0,			0x14 },
	{ PCIE_0_QSERDES_PLL_LOCK_CMP1_MODE1,			0xAA },
	{ PCIE_0_QSERDES_PLL_LOCK_CMP2_MODE1,			0x29 },
	{ PCIE_0_QSERDES_PLL_BG_TRIM,				0x0F },
	{ PCIE_0_QSERDES_PLL_CP_CTRL_MODE0,			0x09 },
	/*PCIE_0_ delay 5ms */
	{ PCIE_PHY_DELAY_MS,					0x05 },
	{ PCIE_0_QSERDES_PLL_CP_CTRL_MODE1,			0x09 },
	{ PCIE_0_QSERDES_PLL_PLL_RCTRL_MODE0,			0x16 },
	{ PCIE_0_QSERDES_PLL_PLL_RCTRL_MODE1,			0x16 },
	{ PCIE_0_QSERDES_PLL_PLL_CCTRL_MODE0,			0x28 },
	{ PCIE_0_QSERDES_PLL_PLL_CCTRL_MODE1,			0x28 },
	{ PCIE_0_QSERDES_PLL_BIAS_EN_CTRL_BY_PSM,		0x01 },
	{ PCIE_0_QSERDES_PLL_SYSCLK_EN_SEL,			0x08 },
	{ PCIE_0_QSERDES_PLL_RESETSM_CNTRL,			0x20 },
	{ PCIE_0_QSERDES_PLL_LOCK_CMP_EN,			0x42 },
	{ PCIE_0_QSERDES_PLL_DEC_START_MODE0,			0x68 },
	{ PCIE_0_QSERDES_PLL_DEC_START_MODE1,			0x53 },
	{ PCIE_0_QSERDES_PLL_DIV_FRAC_START1_MODE0,		0xAB },
	{ PCIE_0_QSERDES_PLL_DIV_FRAC_START2_MODE0,		0xAA },
	{ PCIE_0_QSERDES_PLL_DIV_FRAC_START3_MODE0,		0x02 },
	{ PCIE_0_QSERDES_PLL_DIV_FRAC_START1_MODE1,		0x55 },
	{ PCIE_0_QSERDES_PLL_DIV_FRAC_START2_MODE1,		0x55 },
	{ PCIE_0_QSERDES_PLL_DIV_FRAC_START3_MODE1,		0x05 },
	{ PCIE_0_QSERDES_PLL_INTEGLOOP_GAIN0_MODE0,		0xA0 },
	{ PCIE_0_QSERDES_PLL_INTEGLOOP_GAIN0_MODE1,		0xA0 },
	{ PCIE_0_QSERDES_PLL_VCO_TUNE1_MODE0,			0x24 },
	{ PCIE_0_QSERDES_PLL_VCO_TUNE2_MODE0,			0x02 },
	{ PCIE_0_QSERDES_PLL_VCO_TUNE1_MODE1,			0xB4 },
	{ PCIE_0_QSERDES_PLL_VCO_TUNE2_MODE1,			0x03 },
	{ PCIE_0_QSERDES_PLL_CLK_SELECT,			0x32 },
	{ PCIE_0_QSERDES_PLL_HSCLK_SEL,				0x01 },
	{ PCIE_0_QSERDES_PLL_CORE_CLK_EN,			0x00 },
	{ PCIE_0_QSERDES_PLL_CMN_CONFIG,			0x06 },
	{ PCIE_0_QSERDES_PLL_SVS_MODE_CLK_SEL,			0x05 },
	{ PCIE_0_QSERDES_PLL_CORECLK_DIV_MODE1,			0x08 },
	{ PCIE_0_QSERDES_TX0_RES_CODE_LANE_OFFSET_TX,		0x02 },
	{ PCIE_0_QSERDES_TX0_LANE_MODE_1,			0x06 },
	{ PCIE_0_QSERDES_TX0_RCV_DETECT_LVL_2,			0x12 },
	{ PCIE_0_QSERDES_RX0_UCDR_FO_GAIN,			0x0C },
	{ PCIE_0_QSERDES_RX0_UCDR_SO_GAIN,			0x02 },
	{ PCIE_0_QSERDES_RX0_UCDR_SO_SATURATION_AND_ENABLE,	0x7F },
	{ PCIE_0_QSERDES_RX0_UCDR_PI_CONTROLS,			0x70 },
	{ PCIE_0_QSERDES_RX0_RX_EQU_ADAPTOR_CNTRL2,		0x61 },
	{ PCIE_0_QSERDES_RX0_RX_EQU_ADAPTOR_CNTRL3,		0x04 },
	{ PCIE_0_QSERDES_RX0_RX_EQU_ADAPTOR_CNTRL4,		0x1E },
	{ PCIE_0_QSERDES_RX0_RX_IDAC_TSETTLE_LOW,		0xC0 },
	{ PCIE_0_QSERDES_RX0_RX_IDAC_TSETTLE_HIGH,		0x00 },
	{ PCIE_0_QSERDES_RX0_RX_EQ_OFFSET_ADAPTOR_CNTRL1,	0x73 },
	{ PCIE_0_QSERDES_RX0_RX_OFFSET_ADAPTOR_CNTRL2,		0x80 },
	{ PCIE_0_QSERDES_RX0_SIGDET_ENABLES,			0x1C },
	{ PCIE_0_QSERDES_RX0_SIGDET_CNTRL,			0x03 },
	{ PCIE_0_QSERDES_RX0_SIGDET_DEGLITCH_CNTRL,		0x14 },
	{ PCIE_0_QSERDES_RX0_RX_MODE_00_LOW,			0xF0 },
	{ PCIE_0_QSERDES_RX0_RX_MODE_00_HIGH,			0x01 },
	{ PCIE_0_QSERDES_RX0_RX_MODE_00_HIGH2,			0x2F },
	{ PCIE_0_QSERDES_RX0_RX_MODE_00_HIGH3,			0xD3 },
	{ PCIE_0_QSERDES_RX0_RX_MODE_00_HIGH4,			0x40 },
	{ PCIE_0_QSERDES_RX0_RX_MODE_01_LOW,			0x01 },
	{ PCIE_0_QSERDES_RX0_RX_MODE_01_HIGH,			0x02 },
	{ PCIE_0_QSERDES_RX0_RX_MODE_01_HIGH2,			0xC8 },
	{ PCIE_0_QSERDES_RX0_RX_MODE_01_HIGH3,			0x09 },
	{ PCIE_0_QSERDES_RX0_RX_MODE_01_HIGH4,			0xB1 },
	{ PCIE_0_QSERDES_RX0_RX_MODE_10_LOW,			0x00 },
	{ PCIE_0_QSERDES_RX0_RX_MODE_10_HIGH,			0x02 },
	{ PCIE_0_QSERDES_RX0_RX_MODE_10_HIGH2,			0xC8 },
	{ PCIE_0_QSERDES_RX0_RX_MODE_10_HIGH3,			0x09 },
	{ PCIE_0_QSERDES_RX0_RX_MODE_10_HIGH4,			0xB1 },
	{ PCIE_0_QSERDES_RX0_DFE_EN_TIMER,			0x04 },
	{ PCIE_0_PCS_COM_FLL_CNTRL1,				0x01 },
	{ PCIE_0_PCS_COM_REFGEN_REQ_CONFIG1,			0x0D },
	{ PCIE_0_PCS_COM_G12S1_TXDEEMPH_M3P5DB,			0x10 },
	{ PCIE_0_PCS_COM_RX_SIGDET_LVL,				0xAA },
	{ PCIE_0_PCS_COM_P2U3_WAKEUP_DLY_TIME_AUXCLK_L,		0x01 },
	{ PCIE_0_PCS_COM_RX_DCC_CAL_CONFIG,			0x01 },
	{ PCIE_0_PCS_COM_EQ_CONFIG5,				0x01 },
	{ PCIE_0_PCS_PCIE_POWER_STATE_CONFIG2,			0x0D },
	{ PCIE_0_PCS_PCIE_POWER_STATE_CONFIG4,			0x07 },
	{ PCIE_0_PCS_PCIE_ENDPOINT_REFCLK_DRIVE,		0xC1 },
	{ PCIE_0_PCS_PCIE_L1P1_WAKEUP_DLY_TIME_AUXCLK_L,	0x01 },
	{ PCIE_0_PCS_PCIE_L1P2_WAKEUP_DLY_TIME_AUXCLK_L,	0x01 },
	{ PCIE_0_PCS_PCIE_OSC_DTCT_ACTIONS,			0x00 },
	{ PCIE_0_PCS_PCIE_EQ_CONFIG1,				0x11 },
	{ PCIE_0_PCS_PCIE_PRESET_P10_PRE,			0x00 },
	{ PCIE_0_PCS_PCIE_PRESET_P10_POST,			0x58 },
	{ PCIE_0_PCS_COM_SW_RESET,				0x00 },
	{ PCIE_0_PCS_COM_START_CONTROL,				0x03 },
#endif
};
#endif

enum pcie_verion{
	PCIE_V0,
	PCIE_V1,
	PCIE_V2,
};

static const struct udevice_id pcie_ver_ids[] = {
	{ .compatible = "qcom,ipq806x-pcie", .data = PCIE_V0 },
	{ .compatible = "qcom,ipq40xx-pcie", .data = PCIE_V1 },
	{ .compatible = "qcom,ipq807x-pcie", .data = PCIE_V2 },
	{ .compatible = "qcom,ipq6018-pcie", .data = PCIE_V2 },
	{ .compatible = "qcom,ipq5018-pcie", .data = PCIE_V2 },
	{ .compatible = "qcom,ipq5332-pcie", .data = PCIE_V2 },
	{ .compatible = "qcom,ipq9574-pcie", .data = PCIE_V2 },
	{ },
};

struct ipq_pcie {
	struct pci_controller hose;
	struct fdt_resource pci_dbi;
	struct fdt_resource parf;
	struct fdt_resource elbi;
	struct fdt_resource dm_iatu;
	struct fdt_resource axi_conf;
	struct fdt_resource axi_bars;
	struct fdt_resource pci_rst;
	struct fdt_resource pci_phy;

	int rst_gpio;
	int is_gen3;
	int linkup;
	int version;
	int skip_phy_init;
	int lane;
};

static void ipq_pcie_write_mask(uint32_t addr,
				uint32_t clear_mask, uint32_t set_mask)
{
	uint32_t val;

	val = (readl(addr) & ~clear_mask) | set_mask;
	writel(val, addr);
}

static void ipq_pcie_parf_reset(uint32_t addr, int domain, int assert)

{
	if (assert)
		ipq_pcie_write_mask(addr, 0, domain);
	else
		ipq_pcie_write_mask(addr, domain, 0);
}

void ipq_pcie_config_cfgtype(uint32_t phyaddr)
{
	uint32_t bdf, cfgtype;

	cfgtype = PCI_CFG0_RDWR;
	bdf = MSM_PCIE_DEV_CFG_ADDR;

	writel(0, phyaddr + PCIE20_PLR_IATU_VIEWPORT);

	/* Program Bdf Address */
	writel(bdf, phyaddr + PCIE20_PLR_IATU_LTAR);

	/* Write Config Request Type */
	writel(cfgtype, phyaddr + PCIE20_PLR_IATU_CTRL1);
}

#define PCIE_ATU_CR1_OUTBOUND_6_GEN3			0xC00
#define PCIE_ATU_CR2_OUTBOUND_6_GEN3			0xC04
#define PCIE_ATU_LOWER_BASE_OUTBOUND_6_GEN3		0xC08
#define PCIE_ATU_UPPER_BASE_OUTBOUND_6_GEN3		0xC0C
#define PCIE_ATU_LIMIT_OUTBOUND_6_GEN3			0xC10
#define PCIE_ATU_LOWER_TARGET_OUTBOUND_6_GEN3		0xC14
#define PCIE_ATU_UPPER_TARGET_OUTBOUND_6_GEN3		0xC18

#define PCIE_ATU_CR1_OUTBOUND_7_GEN3			0xE00
#define PCIE_ATU_CR2_OUTBOUND_7_GEN3			0xE04
#define PCIE_ATU_LOWER_BASE_OUTBOUND_7_GEN3		0xE08
#define PCIE_ATU_UPPER_BASE_OUTBOUND_7_GEN3		0xE0C
#define PCIE_ATU_LIMIT_OUTBOUND_7_GEN3			0xE10
#define PCIE_ATU_LOWER_TARGET_OUTBOUND_7_GEN3		0xE14
#define PCIE_ATU_UPPER_TARGET_OUTBOUND_7_GEN3		0xE18

static void dw_pcie_writel_rc_gen3(uint32_t dbi_base, u32 val, u32 reg)
{
		writel(val, dbi_base + reg);
}


void ipq_pcie_prog_outbound_atu(struct ipq_pcie *pcie)
{

	dw_pcie_writel_rc_gen3(pcie->dm_iatu.start, 0x4, PCIE_ATU_CR1_OUTBOUND_6_GEN3);
	dw_pcie_writel_rc_gen3(pcie->dm_iatu.start, 0x90000000, PCIE_ATU_CR2_OUTBOUND_6_GEN3);
	dw_pcie_writel_rc_gen3(pcie->dm_iatu.start, 0x0, PCIE_ATU_LOWER_BASE_OUTBOUND_6_GEN3);
	dw_pcie_writel_rc_gen3(pcie->dm_iatu.start, 0x0, PCIE_ATU_UPPER_BASE_OUTBOUND_6_GEN3);
	dw_pcie_writel_rc_gen3(pcie->dm_iatu.start, 0x00107FFFF, PCIE_ATU_LIMIT_OUTBOUND_6_GEN3);
	dw_pcie_writel_rc_gen3(pcie->dm_iatu.start, 0x0, PCIE_ATU_LOWER_TARGET_OUTBOUND_6_GEN3);
	dw_pcie_writel_rc_gen3(pcie->dm_iatu.start, 0x0, PCIE_ATU_UPPER_TARGET_OUTBOUND_6_GEN3);
	dw_pcie_writel_rc_gen3(pcie->dm_iatu.start, 0x5, PCIE_ATU_CR1_OUTBOUND_7_GEN3);
	dw_pcie_writel_rc_gen3(pcie->dm_iatu.start, 0x90000000, PCIE_ATU_CR2_OUTBOUND_7_GEN3);
	dw_pcie_writel_rc_gen3(pcie->dm_iatu.start, 0x200000, PCIE_ATU_LOWER_BASE_OUTBOUND_7_GEN3);
	dw_pcie_writel_rc_gen3(pcie->dm_iatu.start, 0x0, PCIE_ATU_UPPER_BASE_OUTBOUND_7_GEN3);
	dw_pcie_writel_rc_gen3(pcie->dm_iatu.start, 0x7FFFFF, PCIE_ATU_LIMIT_OUTBOUND_7_GEN3);
	dw_pcie_writel_rc_gen3(pcie->dm_iatu.start, 0x0, PCIE_ATU_LOWER_TARGET_OUTBOUND_7_GEN3);
	dw_pcie_writel_rc_gen3(pcie->dm_iatu.start, 0x0, PCIE_ATU_UPPER_TARGET_OUTBOUND_7_GEN3);

}

int ipq_pcie_rd_conf_byte(struct  pci_controller *hose, pci_dev_t dev,
				     int offset, u8 *val)
{
	int bus = PCI_BUS (dev);
	uint32_t addr;
	uint32_t word_offset, byte_offset, mask;
	uint32_t rd_val;

	word_offset = offset & ~0x3;
	byte_offset = offset & 0x3;
	mask = (~0 >> (8 * (4 - 1))) << (8 * byte_offset);

	ipq_pcie_config_cfgtype(hose->regions[0].phys_start);
	if ((bus == local_buses[0]) || (bus == local_buses[1])) {
		addr = hose->regions[0].phys_start;
	} else {
		addr = hose->regions[1].phys_start;
	}
	rd_val = readl(addr + word_offset);
	*val = ((rd_val & mask) >> (8 * byte_offset));

	return 0;
}

int ipq_pcie_rd_conf_word(struct  pci_controller *hose, pci_dev_t dev,
				     int offset, u16 *val)
{
	int bus = PCI_BUS (dev);
	uint32_t addr;
	uint32_t word_offset, byte_offset, mask;
	uint32_t rd_val;

	word_offset = offset & ~0x3;
	byte_offset = offset & 0x3;
	mask = (~0 >> (8 * (4 - 2))) << (8 * byte_offset);

	ipq_pcie_config_cfgtype(hose->regions[0].phys_start);
	if ((bus == local_buses[0]) || (bus == local_buses[1])) {
		addr = hose->regions[0].phys_start;
	} else {
		addr = hose->regions[1].phys_start;
	}
	rd_val = readl(addr + word_offset);
	*val = ((rd_val & mask) >> (8 * byte_offset));

	return 0;
}
int ipq_pcie_rd_conf_dword(struct  pci_controller *hose, pci_dev_t dev,
				     int offset, u32 *val)
{
	int bus = PCI_BUS (dev);
	uint32_t addr;
	uint32_t word_offset, byte_offset, mask;
	uint32_t rd_val;

	word_offset = offset & ~0x3;
	byte_offset = offset & 0x3;
	mask = (~0 >> (8 * (4 - 4))) << (8 * byte_offset);

	ipq_pcie_config_cfgtype(hose->regions[0].phys_start);
	if ((bus == local_buses[0]) || (bus == local_buses[1])) {
		addr = hose->regions[0].phys_start;
	} else {
		addr = hose->regions[1].phys_start;
	}
	rd_val = readl(addr + word_offset);
	*val = ((rd_val & mask) >> (8 * byte_offset));

	return 0;
}

int ipq_pcie_wr_conf_byte(struct  pci_controller *hose, pci_dev_t dev,
				     int offset, u8 val)
{
	int bus = PCI_BUS (dev);
	uint32_t addr;
	uint32_t word_offset, byte_offset, mask;
	uint32_t rd_val, wr_val;

	word_offset = offset & ~0x3;
	byte_offset = offset & 0x3;
	mask = (~0 >> (8 * (4 - 1))) << (8 * byte_offset);

	ipq_pcie_config_cfgtype(hose->regions[0].phys_start);
	if ((bus == local_buses[0]) || (bus == local_buses[1])) {
		addr = hose->regions[0].phys_start;
	} else {
		addr = hose->regions[1].phys_start;
	}
	rd_val = readl(addr + word_offset);
	wr_val = (rd_val & ~mask) |((val << (8 * byte_offset)) & mask);
	writel(wr_val, addr + word_offset);

	return 0;
}

int ipq_pcie_wr_conf_word(struct  pci_controller *hose, pci_dev_t dev,
				     int offset, u16 val)
{
	int bus = PCI_BUS (dev);
	uint32_t addr;
	uint32_t word_offset, byte_offset, mask;
	uint32_t rd_val, wr_val;

	word_offset = offset & ~0x3;
	byte_offset = offset & 0x3;
	mask = (~0 >> (8 * (4 - 2))) << (8 * byte_offset);

	ipq_pcie_config_cfgtype(hose->regions[0].phys_start);
	if ((bus == local_buses[0]) || (bus == local_buses[1])) {
		addr = hose->regions[0].phys_start;
	} else {
		addr = hose->regions[1].phys_start;
	}
	rd_val = readl(addr + word_offset);
	wr_val = (rd_val & ~mask) |((val << (8 * byte_offset)) & mask);
	writel(wr_val, addr + word_offset);

	return 0;
}

int ipq_pcie_wr_conf_dword(struct  pci_controller *hose, pci_dev_t dev,
				     int offset, u32 val)
{
	int bus = PCI_BUS (dev);
	uint32_t addr;
	uint32_t word_offset, byte_offset, mask;
	uint32_t rd_val, wr_val;

	word_offset = offset & ~0x3;
	byte_offset = offset & 0x3;
	mask = (~0 >> (8 * (4 - 4))) << (8 * byte_offset);

	ipq_pcie_config_cfgtype(hose->regions[0].phys_start);
	if ((bus == local_buses[0]) || (bus == local_buses[1])) {
		addr = hose->regions[0].phys_start;
	} else {
		addr = hose->regions[1].phys_start;
	}
	rd_val = readl(addr + word_offset);
	wr_val = (rd_val & ~mask) |((val << (8 * byte_offset)) & mask);
	writel(wr_val, addr + word_offset);

	return 0;
}

static void ipq_pcie_config_controller(struct ipq_pcie *pcie)
{

	/*
	 * program and enable address translation region 0 (device config
	 * address space); region type config;
	 * axi config address range to device config address range
	 */
	writel(0, pcie->pci_dbi.start + PCIE20_PLR_IATU_VIEWPORT);

	writel(4, pcie->pci_dbi.start + PCIE20_PLR_IATU_CTRL1);
	writel((1 << 31), pcie->pci_dbi.start + PCIE20_PLR_IATU_CTRL2);
	writel(pcie->axi_conf.start , pcie->pci_dbi.start + PCIE20_PLR_IATU_LBAR);
	writel(0, pcie->pci_dbi.start + PCIE20_PLR_IATU_UBAR);
	writel((pcie->axi_conf.start + pcie->axi_conf.end - 1),
				pcie->pci_dbi.start + PCIE20_PLR_IATU_LAR);
	writel(MSM_PCIE_DEV_CFG_ADDR,
				pcie->pci_dbi.start + PCIE20_PLR_IATU_LTAR);
	writel(0, pcie->pci_dbi.start + PCIE20_PLR_IATU_UTAR);

	/*
	 * program and enable address translation region 2 (device resource
	 * address space); region type memory;
	 * axi device bar address range to device bar address range
	 */
	writel(2, pcie->pci_dbi.start + PCIE20_PLR_IATU_VIEWPORT);

	writel(0, pcie->pci_dbi.start + PCIE20_PLR_IATU_CTRL1);
	writel((1 << 31), pcie->pci_dbi.start + PCIE20_PLR_IATU_CTRL2);
	writel(pcie->axi_bars.start, pcie->pci_dbi.start + PCIE20_PLR_IATU_LBAR);
	writel(0, pcie->pci_dbi.start + PCIE20_PLR_IATU_UBAR);
	writel((pcie->axi_bars.start + pcie->axi_bars.end
		- pcie->axi_conf.end - 1), pcie->pci_dbi.start+ PCIE20_PLR_IATU_LAR);
	writel(pcie->axi_bars.start, pcie->pci_dbi.start + PCIE20_PLR_IATU_LTAR);
	writel(0, pcie->pci_dbi.start + PCIE20_PLR_IATU_UTAR);

	/* 1K PCIE buffer setting */
	writel(0x3, pcie->pci_dbi.start + PCIE20_AXI_MSTR_RESP_COMP_CTRL0);
	writel(0x1, pcie->pci_dbi.start + PCIE20_AXI_MSTR_RESP_COMP_CTRL1);
}

void pcie_linkup(struct ipq_pcie *pcie)
{
	int j, val;

	if (pcie->version != PCIE_V2)
	{
		writel(SLV_ADDR_SPACE_SZ, pcie->parf.start + PARF_SLV_ADDR_SPACE_SIZE);
		mdelay(100);
	}

	if (pcie->is_gen3) {
		writel(DEVICE_TYPE_RC, pcie->parf.start + PCIE_PARF_DEVICE_TYPE);
		writel(BYPASS | MSTR_AXI_CLK_EN | AHB_CLK_EN,
			pcie->parf.start + PARF_MHI_CLOCK_RESET_CTRL);
		writel(GEN3_EQUALIZATION_DISABLE | RXEQ_RGRDLESS_RXTS |
			GEN3_ZRXDC_NONCOMPL, pcie->pci_dbi.start + PCIE30_GEN3_RELATED_OFF);
		writel(ECAM_BLOCKER_EN_RANGE2 | MAC_PHY_POWERDOWN_IN_P2_D_MUX_EN
		| ECAM_REMOVE_OFFSET_EN | ECAM_BLOCKER_EN |
		MST_WAKEUP_EN | SLV_WAKEUP_EN | MSTR_ACLK_CGC_DIS
		| SLV_ACLK_CGC_DIS | AUX_PWR_DET |
		CORE_CLK_2AUX_CLK_MUX_DIS | L23_CLK_RMV_DIS,
		pcie->parf.start + PCIE20_PARF_SYS_CTRL);
	}

	writel(0x0, pcie->pci_dbi.start + PCIE_0_PORT_FORCE_REG);
	val = (L1_ENTRANCE_LATENCY(3) |
		L0_ENTRANCE_LATENCY(3) |
		COMMON_CLK_N_FTS(128) |
		ACK_N_FTS(128));
	writel(val, pcie->pci_dbi.start + PCIE_0_ACK_F_ASPM_CTRL_REG);

	val = (FAST_TRAINING_SEQ(128) |
		NUM_OF_LANES(2) |
		DIRECT_SPEED_CHANGE);
	writel(val, pcie->pci_dbi.start + PCIE_0_GEN2_CTRL_REG);
	writel(PCI_TYPE0_BUS_MASTER_EN,
		pcie->pci_dbi.start + PCIE_0_TYPE0_STATUS_COMMAND_REG_1);
	writel(DBI_RO_WR_EN, pcie->pci_dbi.start + PCIE_0_MISC_CONTROL_1_REG);
	writel(0x0002FD7F, pcie->pci_dbi.start + 0x84);

	val = (PCIE_CAP_ASPM_OPT_COMPLIANCE |
		PCIE_CAP_LINK_BW_NOT_CAP |
		PCIE_CAP_DLL_ACTIVE_REP_CAP |
		PCIE_CAP_L1_EXIT_LATENCY(4) |
		PCIE_CAP_L0S_EXIT_LATENCY(4) |
		PCIE_CAP_MAX_LINK_WIDTH(1) |
		PCIE_CAP_MAX_LINK_SPEED(1));
	writel(val, pcie->pci_dbi.start + PCIE_0_LINK_CAPABILITIES_REG);

	writel(PCIE_CAP_CPL_TIMEOUT_DISABLE,
		pcie->pci_dbi.start + PCIE_0_DEVICE_CONTROL2_DEVICE_STATUS2_REG);

	writel(0x10110008, pcie->pci_dbi.start + PCIE_0_TYPE0_LINK_CONTROL_LINK_STATUS_REG_1);

	if (pcie->is_gen3)
		writel(PCIE_CAP_CURR_DEEMPHASIS | SPEED_GEN3,
			pcie->pci_dbi.start + PCIE20_LNK_CONTROL2_LINK_STATUS2);
	writel(LTSSM_EN, pcie->parf.start + PCIE_0_PCIE20_PARF_LTSSM);

	if (pcie->version == PCIE_V2)
		gpio_set_value(pcie->rst_gpio, GPIO_OUT_HIGH);
	mdelay(200);

	for (j = 0; j < 400; j++) {
		val = readl(pcie->pci_dbi.start + PCIE_0_TYPE0_LINK_CONTROL_LINK_STATUS_REG_1);
		if (val & (1 << 29)) {
			printf("PCI Link Intialized\n");
			pcie->linkup = 1;
			break;
		}
		udelay(100);
	}

	if (pcie->is_gen3) {
		writel((pcie->pci_dbi.start + 0x1000), pcie->parf.start + PARF_BLOCK_SLV_AXI_WR_BASE);
		writel((pcie->pci_dbi.start + 0x100000), pcie->parf.start + PARF_BLOCK_SLV_AXI_WR_LIMIT);
		writel((pcie->pci_dbi.start + 0x1000), pcie->parf.start + PARF_BLOCK_SLV_AXI_RD_BASE);
		writel((pcie->pci_dbi.start + 0x100000), pcie->parf.start + PARF_BLOCK_SLV_AXI_RD_LIMIT);
		writel((pcie->pci_dbi.start), pcie->parf.start + PARF_ECAM_BASE);
		writel((pcie->pci_dbi.start + 0x1000), pcie->parf.start + PARF_ECAM_OFFSET_REMOVAL_BASE);
		writel((pcie->pci_dbi.start + 0x200000), pcie->parf.start + PARF_ECAM_OFFSET_REMOVAL_LIMIT);
		writel((pcie->pci_dbi.start + 0x108000), pcie->parf.start + PARF_BLOCK_SLV_AXI_WR_BASE_2);
		writel((pcie->pci_dbi.start + 0x200000), pcie->parf.start + PARF_BLOCK_SLV_AXI_WR_LIMIT_2);
		writel((pcie->pci_dbi.start + 0x108000), pcie->parf.start + PARF_BLOCK_SLV_AXI_RD_BASE_2);
		writel((pcie->pci_dbi.start + 0x200000), pcie->parf.start + PARF_BLOCK_SLV_AXI_RD_LIMIT_2);
		for (j = 0; j < 255; j++)
			writel(0, pcie->parf.start + PARF_BDF_TO_SID_TABLE + (4 * j));
		ipq_pcie_prog_outbound_atu(pcie);
	} else {
		ipq_pcie_config_controller(pcie);
	}
}

void pcie_v0_linkup(struct ipq_pcie *pcie, int id)
{
	int j;
	uint32_t val;
	/* assert PCIe PARF reset while powering the core */
	ipq_pcie_parf_reset(pcie->pci_rst.start, BIT(6), 0);

	ipq_pcie_parf_reset(pcie->pci_rst.start, BIT(2), 1);
	board_pcie_clock_init(id);
	/*
	 * de-assert PCIe PARF reset;
	 * wait 1us before accessing PARF registers
	 */
	ipq_pcie_parf_reset(pcie->pci_rst.start, BIT(2), 0);
	udelay(1);

	/* enable PCIe clocks and resets */
	val = (readl(pcie->parf.start + PCIE20_PARF_PHY_CTRL) & ~BIT(0));
	writel(val, pcie->parf.start + PCIE20_PARF_PHY_CTRL);

	ipq_pcie_write_mask(pcie->parf.start + PCIE20_PARF_PHY_CTRL,
				PHY_CTRL_PHY_TX0_TERM_OFFSET_MASK,
				PHY_CTRL_PHY_TX0_TERM_OFFSET(0));

	/* PARF programming */
	writel(PCIE20_PARF_PCS_DEEMPH_TX_DEEMPH_GEN1(0x18) |
			PCIE20_PARF_PCS_DEEMPH_TX_DEEMPH_GEN2_3_5DB(0x18) |
			PCIE20_PARF_PCS_DEEMPH_TX_DEEMPH_GEN2_6DB(0x22),
			pcie->parf.start + PCIE20_PARF_PCS_DEEMPH);

	writel(PCIE20_PARF_PCS_SWING_TX_SWING_FULL(0x78) |
			PCIE20_PARF_PCS_SWING_TX_SWING_LOW(0x78),
			pcie->parf.start + PCIE20_PARF_PCS_SWING);

	writel((4<<24), pcie->parf.start + PCIE20_PARF_CONFIG_BITS);

	ipq_pcie_write_mask(pcie->parf.start + PCIE20_PARF_PHY_REFCLK,
				REF_USE_PAD, REF_SSP_EN);

	/* enable access to PCIe slave port on system fabric */
	if (id == 0) {
		writel(BIT(4), PCIE_SFAB_AXI_S5_FCLK_CTL);
	}

	udelay(1);
	/* de-assert PICe PHY, Core, POR and AXI clk domain resets */
	ipq_pcie_parf_reset(pcie->pci_rst.start, BIT(5), 0);
	ipq_pcie_parf_reset(pcie->pci_rst.start, BIT(4), 0);
	ipq_pcie_parf_reset(pcie->pci_rst.start, BIT(3), 0);
	ipq_pcie_parf_reset(pcie->pci_rst.start, BIT(0), 0);

	/* enable link training */
	ipq_pcie_write_mask( pcie->elbi.start + PCIE20_ELBI_SYS_CTRL, 0,
			BIT(0));
	udelay(500);

	for (j = 0; j < 10; j++) {
		val = readl(pcie->pci_dbi.start +
				PCIE_0_TYPE0_LINK_CONTROL_LINK_STATUS_REG_1);
		if (val & BIT(29)) {
			printf("PCI%d Link Intialized\n", id);
			pcie->linkup = 1;
			break;
		}
		udelay(10000);
	}
	ipq_pcie_config_controller(pcie);

}

__weak int ipq_sku_pci_validation(int id)
{
	return 0;
}

static int ipq_pcie_parse_dt(const void *fdt, int id,
			       struct ipq_pcie *pcie)
{
	int err, rst_gpio, node;
	char name[16];

	snprintf(name, sizeof(name), "pci%d", id);
	node = fdt_path_offset(fdt, name);
	if (node < 0) {
		printf("PCI%d is not defined in the device tree\n", id);
		return node;
	}

	if (ipq_sku_pci_validation(id)){
		printf("PCI%d is disabled\n", id);
		return 1;
	}

	err = fdt_get_named_resource(fdt, node, "reg", "reg-names", "pci_dbi",
				     &pcie->pci_dbi);
	if (err < 0) {
		error("resource \"pads\" not found");
		return err;
	}

	err = fdt_get_named_resource(fdt, node, "reg", "reg-names", "parf",
				     &pcie->parf);
	if (err < 0) {
		error("resource \"afi\" not found");
		return err;
	}

	err = fdt_get_named_resource(fdt, node, "reg", "reg-names", "elbi",
				     &pcie->elbi);
	if (err < 0) {
		error("resource \"cs\" not found");
		return err;
	}

	err = fdt_get_named_resource(fdt, node, "reg", "reg-names", "axi_bars",
				     &pcie->axi_bars);
	if (err < 0) {
		error("resource \"cs\" not found");
		return err;
	}

	err = fdt_get_named_resource(fdt, node, "reg", "reg-names", "axi_conf",
				     &pcie->axi_conf);
	if (err < 0) {
		error("resource \"cs\" not found");
		return err;
	}

	err = fdt_get_named_resource(fdt, node, "reg", "reg-names", "pci_rst",
				     &pcie->pci_rst);
	if (err < 0) {
		error("resource \"cs\" not found");
		return err;
	}

	pcie->is_gen3 = 0;
	if(pcie->version == PCIE_V2) {
		pcie->is_gen3 = fdtdec_get_int(fdt, node, "gen3", 0);
		err = fdt_get_named_resource(fdt, node, "reg", "reg-names", "pci_phy",
					     &pcie->pci_phy);
		if (err < 0) {
			uint32_t soc_ver_major, soc_ver_minor;
			int ret;

			ret = get_soc_version(&soc_ver_major, &soc_ver_minor);
			if (!ret) {
				if(soc_ver_major == 1) {
					err = fdt_get_named_resource(fdt, node, "reg", "reg-names", "pci_phy_gen2",
							&pcie->pci_phy);
					if (err < 0)
						goto err;
					pcie->is_gen3 = 0;
				} else if(soc_ver_major == 2) {
					err = fdt_get_named_resource(fdt, node, "reg", "reg-names", "pci_phy_gen3",
							&pcie->pci_phy);
					if (err < 0)
						goto err;
					pcie->is_gen3 = 1;
				}
			} else {
				goto err;
			}
		}
		pcie->skip_phy_init =
				fdtdec_get_int(fdt, node, "skip_phy_int", 0);

		pcie->lane = fdtdec_get_int(fdt, node, "lane", 1);
	}
	rst_gpio = fdtdec_get_int(fdt, node, "perst_gpio", 0);
	if (rst_gpio <= 0) {
		debug("PCI: Can't get perst_gpio\n");
		return -1;
	}
	pcie->rst_gpio = rst_gpio;

	if (pcie->is_gen3) {
		err = fdt_get_named_resource(fdt, node, "reg", "reg-names", "dm_iatu",
				&pcie->dm_iatu);
		if (err < 0) {
			error("resource \"dm_iatu\" not found");
			return err;
		}
	}

	return 0;
err:
	error("resource \"phy\" not found");
	return err;
}

#ifndef CONFIG_IPQ806X
void pci_controller_init_v1(struct ipq_pcie *pcie)
{
	uint32_t val;

	/* Assert cc_pcie20_mstr_axi_ares */
	val = readl(pcie->pci_rst.start);
	val |= PCIE_RST_CTRL_AXI_M_ARES;
	writel(val, pcie->pci_rst.start);

	/* Assert cc_pcie20_slv_axi_ares */
	val = readl(pcie->pci_rst.start);
	val |= PCIE_RST_CTRL_AXI_S_ARES;
	writel(val, pcie->pci_rst.start);

	/* Assert cc_pcie20_core_ares */
	writel(PCIE_RST_CTRL_PIPE_ARES, pcie->pci_rst.start);

	/* Assert cc_pcie20_core_sticky_area */
	val = readl(pcie->pci_rst.start);
	val |= PCIE_RST_CTRL_PIPE_STICKY_ARES;
	writel(val, pcie->pci_rst.start);

	/* Assert cc_pcie20_phy_ahb_ares */
	val = readl(pcie->pci_rst.start);
	val |= PCIE_RST_CTRL_PIPE_PHY_AHB_ARES;
	writel(val, pcie->pci_rst.start);

	/* Assert cc_pcie20_mstr_sticky_ares */
	val = readl(pcie->pci_rst.start);
	val |= PCIE_RST_CTRL_AXI_M_STICKY_ARES;
	writel(val, pcie->pci_rst.start);

	gpio_set_value(pcie->rst_gpio, GPIO_OUT_LOW);

	/* Assert cc_pcie20_ahb_ares;  */
	val = readl(pcie->pci_rst.start);
	val |= PCIE_RST_CTRL_AHB_ARES;
	writel(val, pcie->pci_rst.start);

	/* DeAssert cc_pcie20_ahb_ares */
	val = readl(pcie->pci_rst.start);
	val &= ~(PCIE_RST_CTRL_PIPE_PHY_AHB_ARES);
	writel(val, pcie->pci_rst.start);

	/* DeAssert cc_pcie20_pciephy_phy_ares*/
	val = readl(pcie->pci_rst.start);
	val &= ~(PCIE_RST_CTRL_PIPE_ARES);
	writel(val, pcie->pci_rst.start);

	/* DeAssert cc_pcie20_core_sticky_ares */
	val = readl(pcie->pci_rst.start);
	val &= ~(PCIE_RST_CTRL_PIPE_STICKY_ARES);
	writel(val, pcie->pci_rst.start);

	mdelay(5);

	gpio_set_value(pcie->rst_gpio, GPIO_OUT_HIGH);

	/* DeAssert cc_pcie20_mstr_axi_ares */
	val = readl(pcie->pci_rst.start);
	val &= ~(PCIE_RST_CTRL_AXI_M_ARES);
	writel(val, pcie->pci_rst.start);

	/* DeAssert cc_pcie20_mstr_axi_ares */
	val = readl(pcie->pci_rst.start);
	val &= ~(PCIE_RST_CTRL_AXI_M_STICKY_ARES);
	writel(val, pcie->pci_rst.start);

	/* DeAssert cc_pcie20_slv_axi_ares */
	val = readl(pcie->pci_rst.start);
	val &= ~(PCIE_RST_CTRL_AXI_S_ARES);
	writel(val, pcie->pci_rst.start);

	/* DeAssert cc_pcie20_phy_ahb_ares  */
	val = readl(pcie->pci_rst.start);
	val &= ~(PCIE_RST_CTRL_AHB_ARES);
	writel(val, pcie->pci_rst.start);
}

static const struct phy_regs pcie_phy_regs[] = {
#if !defined(CONFIG_IPQ6018)
	{ PCIE_USB3_PCS_POWER_DOWN_CONTROL,			0x00000003 },
	{ QSERDES_COM_BIAS_EN_CLKBUFLR_EN,			0x00000018 },
	{ QSERDES_COM_CLK_ENABLE1,				0x00000010 },
	{ QSERDES_COM_BG_TRIM,					0x0000000f },
	{ QSERDES_COM_LOCK_CMP_EN,				0x00000001 },
	{ QSERDES_COM_VCO_TUNE_MAP,				0x00000000 },
	{ QSERDES_COM_VCO_TUNE_TIMER1,				0x000000ff },
	{ QSERDES_COM_VCO_TUNE_TIMER2,				0x0000001f },
	{ QSERDES_COM_CMN_CONFIG,				0x00000006 },
	{ PCIE_QSERDES_COM_PLL_IVCO,				0x0000000f },
	{ QSERDES_COM_HSCLK_SEL,				0x00000000 },
	{ PCIE_QSERDES_COM_SVS_MODE_CLK_SEL,			0x00000001 },
	{ PCIE_QSERDES_COM_CORE_CLK_EN,				0x00000020 },
	{ QSERDES_COM_CORECLK_DIV,				0x0000000a },
	{ QSERDES_COM_RESETSM_CNTRL,				0x00000020 },
	{ PCIE_QSERDES_COM_BG_TIMER,				0x00000009 },
	{ PCIE_QSERDES_COM_SYSCLK_EN_SEL,			0x0000000a },
	{ PCIE_QSERDES_COM_DEC_START_MODE0,			0x00000082 },
	{ PCIE_QSERDES_COM_DIV_FRAC_START3_MODE0,		0x00000003 },
	{ PCIE_QSERDES_COM_DIV_FRAC_START2_MODE0,		0x00000055 },
	{ PCIE_QSERDES_COM_DIV_FRAC_START1_MODE0,		0x00000055 },
	{ QSERDES_COM_LOCK_CMP3_MODE0,				0x00000000 },
	{ QSERDES_COM_LOCK_CMP2_MODE0,				0x0000000D },
	{ PCIE_QSERDES_COM_LOCK_CMP1_MODE0,			0x00000D04 },
	{ QSERDES_COM_CLK_SELECT,				0x00000033 },
	{ PCIE_QSERDES_COM_SYS_CLK_CTRL,			0x00000002 },
	{ QSERDES_COM_SYSCLK_BUF_ENABLE,			0x0000001f },
	{ QSERDES_COM_CP_CTRL_MODE0,				0x0000000b },
	{ QSERDES_COM_PLL_RCTRL_MODE0,				0x00000016 },
	{ QSERDES_COM_PLL_CCTRL_MODE0,				0x00000028 },
	{ QSERDES_COM_INTEGLOOP_GAIN1_MODE0,			0x00000000 },
	{ QSERDES_COM_INTEGLOOP_GAIN0_MODE0,			0x00000080 },
	{ QSERDES_COM_BIAS_EN_CTRL_BY_PSM,			0x00000001 },
	{ QSERDES_COM_VCO_TUNE_CTRL,				0x0000000a },
	{ QSERDES_COM_SSC_EN_CENTER,				0x00000001 },
	{ PCIE_QSERDES_COM_SSC_PER1,				0x00000031 },
	{ QSERDES_COM_SSC_PER2,					0x00000001 },
	{ QSERDES_COM_SSC_ADJ_PER1,				0x00000002 },
	{ QSERDES_COM_SSC_ADJ_PER2,				0x00000000 },
	{ QSERDES_COM_SSC_STEP_SIZE1,				0x0000002f },
	{ QSERDES_COM_SSC_STEP_SIZE2,				0x00000019 },
	{ QSERDES_TX_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN,		0x00000045 },
	{ QSERDES_TX_LANE_MODE,					0x00000006 },
	{ QSERDES_TX_RES_CODE_LANE_OFFSET,			0x00000002 },
	{ PCIE_QSERDES_TX_RCV_DETECT_LVL_2,			0x00000012 },
	{ QSERDES_RX_SIGDET_ENABLES,				0x0000001c },
	{ PCIE_QSERDES_RX_SIGDET_DEGLITCH_CNTRL,		0x00000014 },
	{ PCIE_QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2,		0x00000001 },
	{ PCIE_QSERDES_RX_RX_EQU_ADAPTOR_CNTRL3,		0x00000000 },
	{ PCIE_QSERDES_RX_RX_EQU_ADAPTOR_CNTRL4,		0x000000db },
	{ QSERDES_RX_UCDR_SO_SATURATION_AND_ENABLE,		0x0000004b },
	{ PCIE_QSERDES_RX_UCDR_SO_GAIN,				0x00000004 },
	{ QSERDES_RX_UCDR_SO_GAIN_HALF,				0x00000004 },
	{ QSERDES_COM_CLK_EP_DIV,				0x00000019 },
	{ PCIE_USB3_PCS_ENDPOINT_REFCLK_DRIVE,			0x00000004 },
	{ PCIE_USB3_PCS_OSC_DTCT_ACTIONS,			0x00000000 },
	{ PCIE_USB3_PCS_PWRUP_RESET_DLY_TIME_AUXCLK,		0x00000040 },
	{ PCIE_USB3_PCS_L1SS_WAKEUP_DLY_TIME_AUXCLK_MSB,	0x00000000 },
	{ PCIE_USB3_PCS_L1SS_WAKEUP_DLY_TIME_AUXCLK_LSB,	0x00000040 },
	{ PCIE_USB3_PCS_PLL_LOCK_CHK_DLY_TIME_AUXCLK_LSB,	0x00000000 },
	{ PCIE_USB3_PCS_LP_WAKEUP_DLY_TIME_AUXCLK,		0x00000040 },
	{ PCIE_USB3_PCS_PLL_LOCK_CHK_DLY_TIME,			0x00000073 },
	{ QSERDES_RX_SIGDET_CNTRL,				0x00000007 },
	{ PCIE_USB3_PCS_RX_SIGDET_LVL,				0x00000099 },
	{ PCIE_USB3_PCS_TXDEEMPH_M6DB_V0,			0x00000015 },
	{ PCIE_USB3_PCS_TXDEEMPH_M3P5DB_V0,			0x0000000e },
	{ PCIE_USB3_PCS_SW_RESET,				0x00000000 },
	{ PCIE_USB3_PCS_START_CONTROL,				0x00000003 },
#endif
};

void pcie_phy_init(struct ipq_pcie *pcie)
{
	int i;
	const struct phy_regs *regs = pcie_phy_regs;

	if (!phy_initialised) {
		writel(0x10000000, pcie->parf.start + 0x358);
		writel(0x10000000, pcie->parf.start + 0x8358);
		mdelay(100);
		phy_initialised = 1;
	}
	for (i = 0; i < ARRAY_SIZE(pcie_phy_regs); i++)
		writel(regs[i].val, pcie->pci_phy.start + regs[i].reg_offset);

}

static inline void qca_pcie_write_reg(u32 base, u32 offset, u32 value)
{
        writel(value, base + offset);
}

void pcie_phy_v2_init(struct ipq_pcie *pcie)
{
	if (!pcie->skip_phy_init) {
		const struct phy_regs *regs = (pcie->lane == 2)?
						pcie_phy_v2_x2_init_seq_ipq :
						pcie_phy_v2_init_seq_ipq;
		int i, size = (pcie->lane == 2)?
				ARRAY_SIZE(pcie_phy_v2_x2_init_seq_ipq)	:
				ARRAY_SIZE(pcie_phy_v2_init_seq_ipq);

		for (i = 0; i < size; i++) {
			if (regs[i].reg_offset == PCIE_PHY_DELAY_MS)
				mdelay(regs[i].val);
			else
				writel(regs[i].val, pcie->pci_phy.start + regs[i].reg_offset);
		}
		mdelay(5);
	}
	return;
}
#endif

static int pci_ipq_ofdata_to_platdata(int id, struct ipq_pcie *pcie)
{

	if (ipq_pcie_parse_dt(gd->fdt_blob, id, pcie))
		return -EINVAL;

	board_pci_init(id);
	switch(pcie->version) {
		case PCIE_V0:
			pcie_v0_linkup(pcie, id);
			break;
#ifndef CONFIG_IPQ806X
		case PCIE_V1:
			pci_controller_init_v1(pcie);
			pcie_linkup(pcie);
			break;
		case PCIE_V2:
			gpio_set_value(pcie->rst_gpio, GPIO_OUT_LOW);
			if (pcie->is_gen3)
				pcie_phy_v2_init(pcie);
			else
				pcie_phy_init(pcie);
			pcie_linkup(pcie);
			break;
#endif
		default:
			break;
	}

	return 0;
}

__weak void ipq_wifi_pci_power_enable(void)
{
	return;
}

void pci_init_board (void)
{
	struct ipq_pcie *pcie;
	int i, bus = 0, ret;
	const struct udevice_id *of_match = pcie_ver_ids;
	unsigned int skip_pci_mask;

	pcie = malloc(sizeof(*pcie));
	if (pcie == NULL) {
		printf("PCI: Init failed. Could't allocate memory\n");
		return;
	}

	while (of_match->compatible) {
		ret = fdt_node_offset_by_compatible(gd->fdt_blob, 0,
						of_match->compatible);
		if (ret < 0) {
			of_match++;
			continue;
		}
		pcie->version = of_match->data;
		break;
	}

	skip_pci_mask = getenv_hex("skip_pci_mask", 0UL);

	ipq_wifi_pci_power_enable();
	for (i = 0; i < PCI_MAX_DEVICES; i++) {
		if (skip_pci_mask & (1UL << i)) {
			printf("Skipping PCI%d\n", i);
			continue;
		}
		pcie->linkup = 0;
		pci_ipq_ofdata_to_platdata(i, pcie);
		if (pcie->linkup) {
			pci_hose[i].first_busno = bus;
			pci_hose[i].last_busno = 0xff;
			local_buses[0] = pci_hose[i].first_busno;

			/* PCI memory space */
			pci_set_region (pci_hose[i].regions + 0,
					pcie->pci_dbi.start,
					pcie->pci_dbi.start,
					PCIE20_SIZE, PCI_REGION_MEM);

			/* PCI device confgiuration  space */
			pci_set_region (pci_hose[i].regions + 1,
					pcie->axi_conf.start,
					pcie->axi_conf.start,
				(PCIE_AXI_CONF_SIZE - 1), PCI_REGION_MEM);

			pci_hose[i].region_count = 2;
			pci_register_hose (&pci_hose[i]);
			pci_set_ops (&pci_hose[i],
				ipq_pcie_rd_conf_byte,
				ipq_pcie_rd_conf_word,
				ipq_pcie_rd_conf_dword,
				ipq_pcie_wr_conf_byte,
				ipq_pcie_wr_conf_word,
				ipq_pcie_wr_conf_dword);

			pci_hose[i].last_busno = pci_hose[i].first_busno + 1;
			bus = pci_hose[i].last_busno + 1;
		}
	}
}

#if defined(CONFIG_IPQ9574) || defined(CONFIG_IPQ5332)
static struct pci_device_id supported_device[] = {
	{QCN_VENDOR_ID, QCN9224_DEVICE_ID},
	{}
};

static void pci_select_window(uint32_t base, uint32_t offset)
{
	u32 window = (offset >> WINDOW_SHIFT) & WINDOW_VALUE_MASK;
	u32 prev_window = 0, curr_window = 0, prev_cleared_window = 0;

	prev_window = readl(base + QCN9224_PCIE_REMAP_BAR_CTRL_OFFSET);

	/* Clear out last 6 bits of window register */
	prev_cleared_window = prev_window & ~(0x3f);

	/* Write the new last 6 bits of window register. Only window 1 values
	 * are changed. Window 2 and 3 are unaffected.
	*/
	curr_window = prev_cleared_window | window;

	writel(WINDOW_ENABLE_BIT | curr_window, base +
	       QCN9224_PCIE_REMAP_BAR_CTRL_OFFSET);
}

static int do_detect_qcn9224(cmd_tbl_t *cmdtp, int flag,
			    int argc, char * const argv[])
{
	pci_dev_t devbusfn;
	uint32_t qcn9224_version = 0;
	struct pci_controller *hose;
	pci_addr_t pci_mem_base, bar0_base;

	devbusfn = pci_find_devices(supported_device, 0);
	if (devbusfn == -1)
		goto out;

	hose = pci_bus_to_hose(PCI_BUS(devbusfn));
	if(hose == NULL)
		goto out;

	/* PCI setup */
	/* Get PCIe base address and map the EP registers to Base + 0x400000, BAR0 */
	pci_mem_base = hose->regions[0].bus_start;
	bar0_base = pci_mem_base + 0x400000;

	pci_write_config_dword (devbusfn, PCI_COMMAND,
			(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER));

	pci_write_config_dword (devbusfn, PCI_BASE_ADDRESS_0, bar0_base);

	/* Read QCN9224 version */
	pci_select_window(bar0_base, QCN9224_TCSR_SOC_HW_VERSION);

	qcn9224_version = readl(bar0_base + WINDOW_START +
				(QCN9224_TCSR_SOC_HW_VERSION & WINDOW_RANGE_MASK));

	qcn9224_version = (qcn9224_version & QCN9224_TCSR_SOC_HW_VERSION_MASK) >>
						QCN9224_TCSR_SOC_HW_VERSION_SHIFT;

	setenv_ulong("qcn9224_version",(unsigned long)qcn9224_version);
out:
	return CMD_RET_SUCCESS;
}

U_BOOT_CMD(detect_qcn9224, 1, 1, do_detect_qcn9224,
	   "Detect qcn9224 version and populate it on qcn9224_version Env",
	   "qcn9224_version will be zero if not attached else one / two");

pci_dev_t pci_find_ipq_devices(struct pci_device_id *ids, int device_id)
{
	struct pci_controller * hose;
	pci_dev_t bdf;
	int bus, index = 0;

	hose = pci_get_hose_head();

	while(hose && device_id && device_id < 4) {
		hose = hose->next;
		device_id--;
	}
	if (hose) {
		for (bus = hose->first_busno; bus <= hose->last_busno; bus++) {
			bdf = pci_hose_find_devices(hose, bus, ids, &index);
			if (bdf != -1)
				return bdf;
		}
	}

	return -1;
}

static int poll_reg_field(pci_addr_t addr, u32 *val, u32 mask, u32 shift, u32 compare)
{
	u32 time_out_ms = 12500;
	u32 delay = 250;
	u32 retry = time_out_ms / delay; /*50 retries*/

	while(retry--) {
		*val = readl(addr);
		if ((*val & mask) >> shift == compare)
			return 0;
		mdelay(delay);
	}

	return -ETIMEDOUT;
}

static void print_error_code(pci_addr_t addr, bool pbl_log)
{
	int i;
	u32 val;
	struct {
		char *name;
		u32 offset;
	} error_reg[] = {
		{ "ERROR_CODE", BHI_ERRCODE },
		{ "ERROR_DBG1", BHI_ERRDBG1 },
		{ "ERROR_DBG2", BHI_ERRDBG2 },
		{ "ERROR_DBG3", BHI_ERRDBG3 },
		{ NULL },
	};

	for (i = 0; error_reg[i].name; i++) {
		val = readl(addr + error_reg[i].offset);
		printf("Reg: %s value: 0x%x\n", error_reg[i].name, val);
	}
	if (pbl_log) {
		pci_select_window(addr, QCN9224_TCSR_PBL_LOGGING_REG);
		val = readl(addr + WINDOW_START + (QCN9224_TCSR_PBL_LOGGING_REG & WINDOW_RANGE_MASK));
		printf("Reg: TCSR_PBL_LOGGING: 0x%x\n", val);
	}

}

int qcn92xx_get_exec_env(pci_addr_t bar)
{
	u32 exec;
	exec = readl(bar + BHI_EXECENV);

	return exec;
}

void qcn92xx_global_soc_reset(pci_addr_t bar)
{
	u32 current_ee;
	u32 count = 0;

	current_ee = qcn92xx_get_exec_env(bar);

	do {
		writel(PCIE_SOC_GLOBAL_RESET_VALUE,
			       PCIE_SOC_GLOBAL_RESET_ADDRESS +
			       bar);
		mdelay(20);
		current_ee = qcn92xx_get_exec_env(bar);
		count++;
	} while (current_ee != 0 &&
		 count < MAX_SOC_GLOBAL_RESET_WAIT_CNT);

	if (count >= MAX_SOC_GLOBAL_RESET_WAIT_CNT)
		printk("SoC global reset failed! Reset count : %d\n",
			      count);
}

static int do_fuse_qcn9224(cmd_tbl_t *cmdtp, int flag,
			    int argc, char * const argv[])
{
	pci_dev_t devbusfn;
	int device_id = 0, ret = 0;
	struct pci_controller *hose;
	pci_addr_t pci_mem_base, bar0_base;
	u16 vendor, device;
	uint32_t load_addr, file_size;
	u32 val = 0, version;

	if (argc != 2)
		return CMD_RET_USAGE;

	device_id = simple_strtoul(argv[1], NULL, 16);

	if (device_id > 3) {
		printf("Supported PCIe instances 0 to 3\n");
		return CMD_RET_USAGE;
	}

	devbusfn = pci_find_ipq_devices(supported_device, device_id);
	if (devbusfn == -1) {
		printf("PCIe %d not enabled\n",device_id);
		return CMD_RET_FAILURE;
	}

	hose = pci_bus_to_hose(PCI_BUS(devbusfn));
	if(hose == NULL) {
		printf("PCI controller hose is NULL\n");
		return CMD_RET_FAILURE;
	}

	pci_mem_base = hose->regions[0].bus_start;
	bar0_base = pci_mem_base + 0x400000;

	pci_read_config_word(devbusfn, PCI_VENDOR_ID, &vendor);
	pci_read_config_word(devbusfn, PCI_DEVICE_ID, &device);
	printf("Fusing on Vendor ID:0x%x device ID:0x%x devbusfn:0x%x\n",
				vendor, device, devbusfn);

	pci_write_config_dword (devbusfn, PCI_COMMAND,
			(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER));

	pci_write_config_dword (devbusfn, PCI_BASE_ADDRESS_0, bar0_base);

	/* Read QCN9224 version */
	pci_select_window(bar0_base, QCN9224_TCSR_SOC_HW_VERSION);

	version = readl(bar0_base + WINDOW_START +
			(QCN9224_TCSR_SOC_HW_VERSION & WINDOW_RANGE_MASK));

	version = (version & QCN9224_TCSR_SOC_HW_VERSION_MASK) >>
					QCN9224_TCSR_SOC_HW_VERSION_SHIFT;

	if (version == 1) {
		printk("Fusing not supported in QCN9224 V1\n");
		return CMD_RET_FAILURE;
	}

	load_addr = getenv_ulong("fileaddr", 16, 0);
	file_size = getenv_ulong("filesize", 16, 0);

	writel(0, bar0_base + BHI_STATUS);
	writel(upper_32_bits(load_addr), bar0_base + BHI_IMGADDR_HIGH);
	writel(lower_32_bits(load_addr), bar0_base + BHI_IMGADDR_LOW);
	writel(file_size, bar0_base + BHI_IMGSIZE);
	writel(1, bar0_base + BHI_IMGTXDB);

	printf("Waiting for fuse blower bin download...\n");
	ret = poll_reg_field(bar0_base + BHI_STATUS, &val, BHI_STATUS_MASK, BHI_STATUS_SHIFT, BHI_STATUS_SUCCESS);
	if (ret) {
		printf("Fuse blower bin Download failed, BHI_STATUS 0x%x, ret %d\n", val, ret);
		print_error_code(bar0_base, true);
		goto fail;
	}

	ret = poll_reg_field(bar0_base + BHI_EXECENV, &val, NO_MASK, 0, 1);
	if (ret) {
		printf("EXECENV is not correct, BHI_EXECENV 0x%x, ret %d\n",val, ret);
		print_error_code(bar0_base, true);
		goto fail;
	}

	printf("Fuse blower bin loaded sucessfully\n");

	ret = poll_reg_field(bar0_base + BHI_ERRCODE, &val, NO_MASK, 0, 0xCAFECACE);
	if (ret) {
		printf("Fusing failed, ret %d\n",ret);
		print_error_code(bar0_base, false);
		goto fail;
	}

	printf("Fusing completed sucessfully\n");

fail:
	/* Target SoC global reset */
	qcn92xx_global_soc_reset(bar0_base);

	mdelay(1000);

	/* Target MHI reset */
	val = readl(bar0_base + MHICTRL);
	writel(val | MHICTRL_RESET_MASK, bar0_base + MHICTRL);

	return CMD_RET_SUCCESS;
}

U_BOOT_CMD(fuse_qcn9224, 2, 1, do_fuse_qcn9224,
	   "Fuse QCN9224 V2 fuses and argument is PCIe device ID",
	   "If not QCN9224 V2, then fuse blow will be skipped");

static struct pci_device_id pci_device[] = {
	{QCN_VENDOR_ID, QCN9224_DEVICE_ID},
	{QCN_VENDOR_ID, QCN9000_DEVICE_ID},
	{QCN_VENDOR_ID, QCN6432_DEVICE_ID},
	{}
};

static int do_list_pci(cmd_tbl_t *cmdtp, int flag,
			    int argc, char * const argv[])
{
	pci_dev_t devbusfn;
	struct pci_controller *hose;
	int device_id;
	u16 vendor,device;

	printf(" PCIe Bus Number \t Base Address \t Device ID \n");
	for(device_id = 0; device_id < 4; device_id++) {
		devbusfn = pci_find_ipq_devices(pci_device, device_id);
		if (devbusfn == -1)
			continue;

		hose = pci_bus_to_hose(PCI_BUS(devbusfn));
		if(hose == NULL)
			continue;

		pci_read_config_word(devbusfn, PCI_VENDOR_ID, &vendor);
		pci_read_config_word(devbusfn, PCI_DEVICE_ID, &device);

		printf("\t %d\t\t  0x%x \t 0x%x \n", device_id,
				hose->regions[0].bus_start, PCI_VENDEV(vendor,device));
	}

	return CMD_RET_SUCCESS;
}

U_BOOT_CMD(list_pci, 1, 1, do_list_pci,
	   "Print the RC's PCIe details and attached device ID",
	   "If no attach is present, then nothing will be printed");

static int do_list_qcn9224_fuse(cmd_tbl_t *cmdtp, int flag,
			    int argc, char * const argv[])
{
	pci_dev_t devbusfn;
	struct pci_controller *hose;
	pci_addr_t pci_mem_base, bar0_base;
	int device_id;
	u32 val;
	int i;

	for(device_id = 0; device_id < 4; device_id++) {
		devbusfn = pci_find_ipq_devices(supported_device, device_id);
		if (devbusfn == -1)
			continue;

		hose = pci_bus_to_hose(PCI_BUS(devbusfn));
		if(hose == NULL)
			continue;

		pci_mem_base = hose->regions[0].bus_start;
		bar0_base = pci_mem_base + 0x400000;

		pci_write_config_dword (devbusfn, PCI_COMMAND,
				(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER));

		pci_write_config_dword (devbusfn, PCI_BASE_ADDRESS_0, bar0_base);

		printf("PCIe Bus ID: %d\nFuse Name \t\t Address \t Value\n",device_id);
		printf("------------------------------------------------------\n");

		pci_select_window(bar0_base, QCN9224_SECURE_BOOT0_AUTH_EN);

		val = readl(bar0_base + WINDOW_START +
				(QCN9224_SECURE_BOOT0_AUTH_EN & WINDOW_RANGE_MASK));

		printf("SECURE_BOOT0_AUTH_EN\t   0x%x \t 0x%x \n", QCN9224_SECURE_BOOT0_AUTH_EN,
				(val & QCN9224_SECURE_BOOT0_AUTH_EN_MASK));


		pci_select_window(bar0_base, QCN9224_OEM_MODEL_ID);

		val = readl(bar0_base + WINDOW_START +
				(QCN9224_OEM_MODEL_ID & WINDOW_RANGE_MASK));

		printf("OEM ID\t\t\t   0x%x \t 0x%lx \n",QCN9224_OEM_MODEL_ID,
				(val & QCN9224_OEM_ID_MASK) >> QCN9224_OEM_ID_SHIFT);
		printf("MODEL ID\t\t   0x%x \t 0x%lx \n",QCN9224_OEM_MODEL_ID,
				(val & QCN9224_MODEL_ID_MASK));

		pci_select_window(bar0_base, QCN9224_ANTI_ROLL_BACK_FEATURE);

		val = readl(bar0_base + WINDOW_START +
				(QCN9224_ANTI_ROLL_BACK_FEATURE & WINDOW_RANGE_MASK));
		printf("ANTI_ROLL_BACK_FEATURE_EN  0x%x \t 0x%lx \n", QCN9224_ANTI_ROLL_BACK_FEATURE,
				(val & QCN9224_ANTI_ROLL_BACK_FEATURE_EN_MASK) >> QCN9224_ANTI_ROLL_BACK_FEATURE_EN_SHIFT);
		printf("TOTAL_ROT_NUM\t\t   0x%x \t 0x%lx \n", QCN9224_ANTI_ROLL_BACK_FEATURE,
				(val & QCN9224_TOTAL_ROT_NUM_MASK) >> QCN9224_TOTAL_ROT_NUM_SHIFT);
		printf("ROT_REVOCATION\t\t   0x%x \t 0x%lx \n", QCN9224_ANTI_ROLL_BACK_FEATURE,
				(val & QCN9224_ROT_REVOCATION_MASK) >> QCN9224_ROT_REVOCATION_SHIFT);
		printf("ROT_ACTIVATION\t\t   0x%x \t 0x%lx \n", QCN9224_ANTI_ROLL_BACK_FEATURE,
				(val & QCN9224_ROT_ACTIVATION_MASK) >> QCN9224_ROT_ACTIVATION_SHIFT);

		for(i = 0; i <= QCN9224_OEM_PK_HASH_SIZE ; i+=4) {
			pci_select_window(bar0_base, QCN9224_OEM_PK_HASH + i);

			val = readl(bar0_base + WINDOW_START +
					((QCN9224_OEM_PK_HASH + i) & WINDOW_RANGE_MASK));

			printf("OEM PK hash \t\t   0x%x \t 0x%x\n",QCN9224_OEM_PK_HASH + i, val);
		}

		pci_select_window(bar0_base, QCN9224_JTAG_ID);
		val = readl(bar0_base + WINDOW_START +
				(QCN9224_JTAG_ID & WINDOW_RANGE_MASK));

		for(i = 0; i < ARRAY_SIZE(qcn9224_jtag_ids); i++) {
			if(qcn9224_jtag_ids[i].id == val) {
				printf("JTAG ID\t\t\t   0x%x \t 0x%x(%s)\n",
						QCN9224_JTAG_ID, val, qcn9224_jtag_ids[i].name);
				break;
			}
		}
		if(i >= ARRAY_SIZE(qcn9224_jtag_ids))
			printf("JTAG ID\t\t\t   0x%x \t 0x%x\n", QCN9224_JTAG_ID, val);

		pci_select_window(bar0_base, QCN9224_SERIAL_NUM);
		val = readl(bar0_base + WINDOW_START +
				(QCN9224_SERIAL_NUM & WINDOW_RANGE_MASK));
		printf("Serial Number\t\t   0x%x \t 0x%x\n", QCN9224_SERIAL_NUM, val);

		pci_select_window(bar0_base, QCN9224_PART_TYPE_EXTERNAL);
		val = readl(bar0_base + WINDOW_START +
				(QCN9224_PART_TYPE_EXTERNAL & WINDOW_RANGE_MASK));
		val = (val & QCN9224_PART_TYPE_EXTERNAL_MASK) >> QCN9224_PART_TYPE_EXTERNAL_SHIFT;
		printf("Part Type\t\t   0x%x \t 0x%x(%s)\n", QCN9224_PART_TYPE_EXTERNAL, val,
				val?"EXT":"INT");

		printf("------------------------------------------------------\n\n");
	}

	return CMD_RET_SUCCESS;
}

U_BOOT_CMD(list_qcn9224_fuse, 1, 1, do_list_qcn9224_fuse,
	   "Print QCN9224 fuse details from attached PCIe slots",
	   "If there is no QCN9224 attach, then nothing will be printed");

#endif
